
var Character = function(id, image, type) {
  this.charType = type;
  this.deleteFlag = 0;
  this.charElement = $('character-'+id);
  var moveCode = [];
  var charID = id;
  var charObserver = null;
  var speed = 80;
  var bombType = 1;
  var bombLevel = 1;
  var bombLimit = 1;
  var bombCount = 0;
  var poisonLimit = 0;
  var imageType = image;
  /* ------------------------------------------------------------+/
   * イベント監視(public)
   * 
   * ------------------------------------------------------------*/
  this.setObserver = function() {
    if (charObserver !== null) {
      clearInterval(charObserver);
    }
    charObserver = null;
    charObserver = _eventExecute.applyInterval(this, [], speed);
  }
  /* ------------------------------------------------------------+/
   * イベント実行(private)
   * 
   * ------------------------------------------------------------*/
  var _eventExecute = function() {
    for(var i in moveCode) if (moveCode[i]) this.move(moveCode[i])
  }
  /* ------------------------------------------------------------+/
   * 移動イベント配置(public)
   * 
   * ------------------------------------------------------------*/
  this.setMoveEvent = function(hash, code) {
    moveCode[hash] = code;
  }
  /* ------------------------------------------------------------+/
   * 移動イベント停止(public)
   * 
   * ------------------------------------------------------------*/
  this.stopMoveEvent = function(hash) {
    moveCode[hash] = null;
    
    this.charElement.src = this.charElement.src.replace('_', '');
  }
  /* ------------------------------------------------------------+/
   * 移動処理(public)
   * 
   * ------------------------------------------------------------*/
  this.move = function(movePoint) {
    this.charElement.src = '/images/bomber/character/_'+imageType+'-'+movePoint+'.gif';
    
    // 左右
    if (movePoint <= 2 && Math.abs(parseInt(this.charElement.style.top) % PanelSize - parseInt(OneStep * PanelWeight * 0.55)) > parseInt(OneStep * PanelWeight * 0.25)) {
      this.moveExecute('left', ((movePoint * 2 - 3) * OneStep));
    }
    // 上下
    else if (movePoint > 2 && Math.abs(parseInt(this.charElement.style.left) % PanelSize - parseInt(OneStep * PanelWeight * 0.55)) > parseInt(OneStep * PanelWeight * 0.25)) {
      this.moveExecute('top', ((movePoint * 2 - 7) * OneStep));
    }
  }
  /* ------------------------------------------------------------+/
   * 移動実行(public)
   * 
   * ------------------------------------------------------------*/
  this.moveExecute = function(tarCoord, movePoint) {
    var adjustCoord = tarCoord == 'top' ? 'left' : 'top';
    
    // マス目調整
    this.charElement.style[adjustCoord] = this.normalize(parseInt(this.charElement.style[adjustCoord])) + 'px';
    
    // 目標座標
    var etop = parseInt(parseInt(this.charElement.style.top)/PanelSize);
    var eleft = parseInt(parseInt(this.charElement.style.left)/PanelSize);
    if (movePoint > 0) {
      if (tarCoord == 'top' && etop < PanelArticle - 1)
        etop += movePoint/OneStep;
      if (tarCoord == 'left' && eleft < PanelArticle - 1)
        eleft += movePoint/OneStep;
    }
    else if (movePoint < 0 && parseInt(this.charElement.style[tarCoord]) % PanelSize == 0) {
      if (tarCoord == 'top' && etop > 0)
        etop -= 1;
      if (tarCoord == 'left' && eleft > 0)
        eleft -= 1;
    }
    
    // 障害物がなければ移動
    if (Blocks[etop][eleft] == 0) {
      // 両端の場合ははみ出ないように修正
      this.charElement.style[tarCoord] = _adjustDistance(parseInt(this.charElement.style[tarCoord]), movePoint) + 'px';
      
      // イベント処理
      if (Events[etop][eleft] < 0 || (this.charType != -1 && Events[etop][eleft] > 0))
        this.getEvent(etop, eleft);
    }
  }
  /* ------------------------------------------------------------+/
   * 距離調整(private)
   * 
   * ------------------------------------------------------------*/
  var _adjustDistance = function(coord, movePoint) {
    var adjuseCoord;
    if(coord + movePoint >= PanelSize * (PanelArticle - 1))
      adjuseCoord = PanelSize * (PanelArticle - 1);
    else if (coord + movePoint <= 0)
      adjuseCoord = 0;
    else
      adjuseCoord = coord + movePoint;
    
    return adjuseCoord;
  }
  /* ------------------------------------------------------------+/
   * イベント処理(public)
   * 
   * ------------------------------------------------------------*/
  this.getEvent = function(itop, ileft) {
    switch(Events[itop][ileft]) {
      // 火力
      case 1:
        bombLevel++;
        break;
      // スピード
      case 2:
        speed = speed >= 20 ? speed - 10 : 10;
        this.setObserver();
        break;
      // 弾数
      case 3:
        bombLimit++;
        break;
      // 毒の道具
      case 4:
        poisonLimit++;
        break;
      // 時間ストップ
      case 5:
        break;
      // スピードダウン
      case 6:
        speed += 5;
        this.setObserver();
        break;
      // 毒パネル踏んだ
      case -4:
        this.deleteChar();
        break;
      default:
        break;
    }
    
    if (Events[itop][ileft] != 0) {
      Events[itop][ileft] = 0;
      $('panel-'+itop+'-'+ileft).style.background = '';
    }
  }
  /* ------------------------------------------------------------+/
   * 爆弾配置(public)
   * 
   * ------------------------------------------------------------*/
  this.setBomb = function() {
    var charTop = parseInt(this.charElement.style.top);
    var charLeft = parseInt(this.charElement.style.left);
    if (
      bombLimit > bombCount && 
      Math.abs(charTop % PanelSize - parseInt(OneStep * PanelWeight * 0.5)) > parseInt(OneStep * PanelWeight * 0.05) && 
      Math.abs(charLeft % PanelSize - parseInt(OneStep * PanelWeight * 0.5)) > parseInt(OneStep * PanelWeight * 0.05)
    ) {
      charTop  = this.normalize(charTop);
      charLeft = this.normalize(charLeft);
      
      var etop = charTop / PanelSize;
      var eleft = charLeft / PanelSize;
      if (Blocks[etop][eleft] == 0) {
        var bomb = document.createElement('img');
        bomb.id = 'bomb-'+etop+'-'+eleft;
        bomb.className = 'bomb';
        bomb.src = '/images/bomber/bomb/'+bombType+'.gif';
        bomb.style.top = charTop + 'px';
        bomb.style.left = charLeft + 'px';
        bomb.style.width = PanelSize + 'px';
        bomb.style.height = PanelSize + 'px';
        MainPanel.appendChild(bomb);
        
        // 爆破タイマー設定
        BombTimer[etop+'-'+eleft] = this.blowUp.applyTimeout(this, [etop, eleft], 4000);
        
        Blocks[etop][eleft] = -5;
        bombCount++;
      }
    }
  }
  /* ------------------------------------------------------------+/
   * 爆発(public)
   * 
   * ------------------------------------------------------------*/
  this.blowUp = function(top, left) {
    MainPanel.removeChild($('bomb-'+top+'-'+left));
    
    // 爆発エフェクト(設置箇所)
    $('panel-'+top+'-'+left).style.backgroundColor = '#000000';
    _clearBlowEffect.applyTimeout(this, [top, left], 500);
    
    Blocks[top][left] = 0;
    bombCount--;
    
    // 被爆判定
    _deleteCheck(top, left);
    
    // 爆発エフェクトとか(設置箇所以外)
    this.blowUpLocator(top, left);
  }
  /* ------------------------------------------------------------+/
   * 爆発処理(public)
   * 
   * ------------------------------------------------------------*/
  this.blowUpLocator = function(btop, bleft) {
    for (var tarCoord=0;tarCoord<=1;tarCoord++) {
      for (var i=0;i<=1;i++) {
        var code = i ? 1 : -1;
        for (var bombLine=1;bombLine<=bombLevel;bombLine++) {
          var secterTop = tarCoord ? btop + bombLine * code : btop;
          var secterLeft = tarCoord ? bleft : bleft + bombLine * code;
          if (
           (code == -1 && secterTop >= 0 && secterLeft >= 0 && Blocks[secterTop][secterLeft] != -2)
           || 
           (code == 1 && secterTop < PanelArticle && secterLeft < PanelArticle && Blocks[secterTop][secterLeft] != -2)
          ) {
            // 爆発エフェクト
            $('panel-'+secterTop+'-'+secterLeft).style.backgroundColor = '#000000';
            _clearBlowEffect.applyTimeout(this, [secterTop, secterLeft], 500);
            
            // 破壊可能な壁の場合消去
            if (Blocks[secterTop][secterLeft] == -1) {
              Blocks[secterTop][secterLeft] = 0;
              
              // アイテムが下にある場合表示
              if (Events[secterTop][secterLeft] != 0) {
                $('panel-'+secterTop+'-'+secterLeft).style.background = 'url(/images/bomber/item/1.gif) center center no-repeat';
              }
              else {
                $('panel-'+secterTop+'-'+secterLeft).style.backgroundImage = 'url()';
              }
              
              // ブロックを破壊した場合、次以降のマスは歯止めがかかる
              break;
            }
            // 連鎖
            else if (Blocks[secterTop][secterLeft] == -5) {
              clearTimeout(BombTimer[secterTop+'-'+secterLeft]);
              BombTimer[secterTop+'-'+secterLeft] = null;
              
              this.blowUp(secterTop, secterLeft);
            }
            // アイテム消去
            else if (Events[secterTop][secterLeft] != 0) {
              Events[secterTop][secterLeft] = 0;
              $('panel-'+secterTop+'-'+secterLeft).style.backgroundImage = 'url()';
            }
            
            // 被爆判定
            _deleteCheck(secterTop, secterLeft);
          }
          else {
            break;
          }
        }
      }
    }
  }
  /* ------------------------------------------------------------+/
   * 爆発エフェクト除去(private)
   * 
   * ------------------------------------------------------------*/
  var _clearBlowEffect = function(top, left) {
    $('panel-'+top+'-'+left).style.backgroundColor = 'transparent';
  }
  /* ------------------------------------------------------------+/
   * 毒パネル配置(public)
   * 
   * ------------------------------------------------------------*/
  this.setPoisonPanel = function() {
    var charTop = parseInt(this.charElement.style.top);
    var charLeft = parseInt(this.charElement.style.left);
    if (
      poisonLimit > 0 && 
      Math.abs(charTop % PanelSize - parseInt(OneStep * PanelWeight * 0.5)) > parseInt(OneStep * PanelWeight * 0.05) && 
      Math.abs(charLeft % PanelSize - parseInt(OneStep * PanelWeight * 0.5)) > parseInt(OneStep * PanelWeight * 0.05)
    ) {
      charTop  = this.normalize(charTop);
      charLeft = this.normalize(charLeft);
      
      var etop = charTop / PanelSize;
      var eleft = charLeft / PanelSize;
      if (eleft < PanelSize / (PanelArticle - 1)) {
        eleft++;
      }
      else {
        eleft--;
      }
      
      if (Blocks[etop][eleft] == 0 && Events[etop][eleft] == 0) {
        $('panel-'+etop+'-'+eleft).style.background = 'url(/images/bomber/common/poison.gif) center center no-repeat';
        
        Events[etop][eleft] = -4;
        poisonLimit--;
      }
    }
  }
  /* ------------------------------------------------------------+/
   * AI作成(public)
   * 
   * ------------------------------------------------------------*/
  this.setAI = function() {
    // 移動速度調整
    speed = this.charType == -1 ? speed * 3 : speed * 2;
    
    if (charObserver !== null) {
      clearInterval(charObserver);
    }
    charObserver = null;
    charObserver = _eventExecuteAI.applyInterval(this, [], speed);
  }
  /* ------------------------------------------------------------+/
   * AIイベント実行(private)
   * 
   * ------------------------------------------------------------*/
  var _eventExecuteAI = function() {
    var moveArray = [1, 3, 2, 4];
    var modePoint = _grep(moveCode, '[0-9]');
    if (modePoint == -1) {
      modePoint = Math.floor(Math.random() * 4);
      moveCode[modePoint] = moveArray[modePoint];
    }
    
    // 目的座標
    var etop = parseInt(parseInt(this.charElement.style.top)/PanelSize);
    var eleft = parseInt(parseInt(this.charElement.style.left)/PanelSize);
    if (modePoint >= 2) {
      if (modePoint == 3 && etop < PanelArticle - 1)
        etop += 1;
      if (modePoint == 2 && eleft < PanelArticle - 1)
        eleft += 1;
    }
    else if (modePoint < 2) {
      if (modePoint == 1 && etop > 0 && parseInt(this.charElement.style.top) % PanelSize == 0)
        etop -= 1;
      if (modePoint == 0 && eleft > 0 && parseInt(this.charElement.style.left) % PanelSize == 0)
        eleft -= 1;
    }
    
    // 座標移動
    var chk = this.chkPosition(modePoint);
    if (Blocks[etop][eleft] == 0 && chk) {
      this.move(moveCode[modePoint]);
    }
    else {
      this.move(moveCode[modePoint]);
      moveCode[modePoint] = null;
    }
    
    // AIの場合ランダムで爆弾設置
    if (this.charType == 1 && !Math.floor(Math.random() * 15))
      this.setBomb();
    
    // プレイヤー接触判定(敵のみ実行)
    if (this.charType == -1)
      _deleteCheck((parseInt(this.charElement.style.top) / PanelSize), (parseInt(this.charElement.style.left) / PanelSize), charID);
  }
  /* ------------------------------------------------------------+/
   * 死亡判定(private)
   * 
   * ------------------------------------------------------------*/
  var _deleteCheck = function(top, left, selfThrough) {
    var delCount = [0, 0];
    for (var num=1;num<=AllCharacterCount;num++) {
      if (
        Math.abs(parseInt(Characters[num].charElement.style.top)  - top  * PanelSize) < PanelSize && 
        Math.abs(parseInt(Characters[num].charElement.style.left) - left * PanelSize) < PanelSize && 
        Characters[num].deleteFlag == 0 && 
        (!selfThrough || (selfThrough && num != selfThrough && Characters[num].charType != -1))
      )
        Characters[num].deleteChar();
      
      if (num <= UseCharacterNum && Characters[num].deleteFlag == 1)
        delCount[0]++
      else if(num > UseCharacterNum && Characters[num].deleteFlag == 1)
        delCount[1]++
    }
    if (delCount[0] == UseCharacterNum)
      $('result').innerHTML = '味方全滅 ';
    else if (delCount[1] == AllCharacterCount - UseCharacterNum)
      $('result').innerHTML = '敵全滅！！ ';
  }
  /* ------------------------------------------------------------+/
   * 死亡処理(public)
   * 
   * ------------------------------------------------------------*/
  this.deleteChar = function() {
    this.deleteFlag = 1;
    
    if (charObserver) {
      clearInterval(charObserver);
    }
    charObserver = null;
    
    // 死亡エフェクト
    var dead = document.createElement('img');
    dead.id = 'dead-'+charID;
    dead.className = 'dead';
    dead.src = '/images/bomber/common/dead.gif';
    dead.style.top = parseInt(this.charElement.style.top) + 'px';
    dead.style.left = parseInt(this.charElement.style.left) + 'px';
    dead.style.width = PanelSize + 'px';
    dead.style.height = PanelSize + 'px';
    MainPanel.appendChild(dead);
    
    // 死亡エフェクト除去
    _clearDeadEffect.applyTimeout(this, [charID], 500);
    
    // キャラクター要素削除
    MainPanel.removeChild(this.charElement);
    
    this.setBomb = function() {}
    
    $('param').innerHTML += ' ' + charID + ' killed. ';
  }
  /* ------------------------------------------------------------+/
   * 死亡エフェクト除去(private)
   * 
   * ------------------------------------------------------------*/
  var _clearDeadEffect = function(id) {
    MainPanel.removeChild($('dead-'+id));
  }
  /* ------------------------------------------------------------+/
   * 位置判定(public)
   * 
   * ------------------------------------------------------------*/
  this.chkPosition = function(modePoint) {
    var chk = false;
    if(
      (modePoint == 0 && parseInt(this.charElement.style.left) != 0) || 
      (modePoint == 1 && parseInt(this.charElement.style.top) != 0) || 
      (modePoint == 2 && parseInt(this.charElement.style.left) != parseInt(PanelSize * (PanelArticle - 1))) || 
      (modePoint == 3 && parseInt(this.charElement.style.top) != parseInt(PanelSize * (PanelArticle - 1)))
    ) { chk = true }
    
    return chk;
  }
  /* ------------------------------------------------------------+/
   * 正規化(public)
   * 
   * ------------------------------------------------------------*/
  this.normalize = function(coord) {
    if (coord % PanelSize <= parseInt(OneStep * PanelWeight * 0.4))
      coord = coord - coord % PanelSize;
    else if (coord % PanelSize >= parseInt(OneStep * PanelWeight * 0.8))
      coord = coord + PanelSize - (coord % PanelSize);
    
    return coord;
  }
  /* ------------------------------------------------------------+/
   * Grep検索(private)
   * 
   * ------------------------------------------------------------*/
  var _grep = function(array, val) {
    for (var i in array)
      if (array[i] && array[i].toString().match(new RegExp(val, 'gi'))) return i;
    return -1;
  }
  /* ------------------------------------------------------------+/
   * デバッガ(public)
   * 
   * ------------------------------------------------------------*/
  this.debug = function() {
    $('debug').innerHTML = '     Date: '	+ new Date().getTime() + 
                           ' ... CID: '		+ charID + 
                           ' ... CType: '	+ this.charType + 
                           ' ... CObs: '	+ charObserver + '[' + this.deleteFlag +  ']' + 
                           ' ... Coord: ['	+ this.charElement.style.top + ', ' + this.charElement.style.left + ']' + 
                           ' ... Speed:'	+ speed + 
                           ' ... BType:'	+ bombType + 
                           ' ... BLevel:'	+ bombLevel + 
                           ' ... BLimit: '	+ bombLimit + 
                           ' ... BCount: '	+ bombCount + 
                           ' ... PLimit: '	+ poisonLimit;
  }
}


