var STATE_CLEAR = 0;
var STATE_SPLIT = 1;
var STATE_MERGE = 2;

function Move(board, color, id, validator, cloneCallback) {
  this.color = color;
  this.id = id;
  this.originalBoard = board;
  this.validator = validator;
  this.cloneCallback = cloneCallback;
  this.reset();
}

Move.prototype.reset = function() {
  this.board = this.originalBoard.clone(this.cloneCallback);
  this.state = STATE_CLEAR;
  this.splitDir = UNKNOWN_DIR;
  this.splitLine = ZERO;
  this.splitStart = null;
  this.splitEnd = null;
  this.mergeLeftTop = null;
  this.mergeLeftBottom = null;
  this.mergeRightTop = null;
  this.mergeRightBottom = null;
  this.message = "";
  this.swappablePieces = new Array();
  this.swappedPieces = new Array();
  this.numSwappedPieces = 0;
  this.winningColor = NULL_COLOR;
  this.board.evaluate();
  this.capturedAtSwap = false;
}

Move.prototype.split = function(piece, dir) {
  if (this.validator.isEnabled()) {
	  if (piece.color != this.color) {
	    this.message = "You can't split your opponent's piece";
	    return;
	  }
	  if (this.state == STATE_MERGE) {
	    this.message = "Can not split. Already merging";
	    return;
	  }
  }
  if (!piece.canSplit(dir)) {
    this.message = "The piece can not be split in " + DIR_TEXT[dir] + " direction";
    return;
  }
  if (!this.validator.isEnabled()) {
      this.board.split(piece,dir);
      this.message = ""; 
      return;
  }
  if (this.state == STATE_CLEAR) {
    this.state = STATE_SPLIT;
    this.splitDir = dir;
    this.splitLine = piece.getMiddle(dir);
    this.splitStart = piece.start[dir];
    this.splitEnd = piece.end[dir];
    this._addToSwappablePieces(this.board.split(piece, dir));
    this.message = "";
  } else if (this.state == STATE_SPLIT && this.splitDir == dir && piece.getMiddle(dir).equals(this.splitLine)) {
    if (piece.start[dir].equals(this.splitEnd)) {
      this.splitEnd = piece.end[dir];
    } else if (piece.end[dir].equals(this.splitStart)) {
      this.splitStart = piece.start[dir];
    } else {
      this.message = "The piece is not adjacent to the previous split piece";
      return;
    }
    this._addToSwappablePieces(this.board.split(piece, dir));
    this.message = "";
  } else {
    this.message = "The piece is not a part of long split";
  }
}

Move.prototype.splitOrSwap = function(piece, dir) {
  if (this.numSwappedPieces > 0 && this._swappable(piece)) {
    this.swap(piece);
  } else {
    this.split(piece,dir);
  }
}

Move.prototype.longSplit = function(pFirst, pLast, dir) {
  if (this.validator.isEnabled()) {
	  if (pFirst.color != this.color || pLast.color != this.color) {
	    this.message = "You can't split your opponent's piece";
	    return;
	  }
	  if (this.state == STATE_MERGE) {
	    this.message = "Can not do long split. Already merging";
	    return;
	  }
  }
  if (!pFirst.canSplit(dir)) {
    this.message = "The piece can not be split in " + DIR_TEXT[dir] + " direction";
    return;
  }
  if (!this.validator.isEnabled()) {
    this.board.longSplit(pFirst, pLast, dir);
    this.message = "";
    return;
  }
  if (this.state == STATE_CLEAR) {
    this.state = STATE_SPLIT;
    this.splitDir = dir;
    this.splitLine = pFirst.getMiddle(dir);
    this.splitStart = pFirst.start[dir];
    this.splitEnd = pLast.end[dir];
    assert(!pFirst.end[dir].bigger(pLast.start[dir]));
    var res = this.board.longSplit(pFirst, pLast, dir);
    if (res.length == 0) {
      this.message = "Failed to do long split"
      return;
    }
    this._addToSwappablePieces(res);
    this.message = "";
  } else if (this.state == STATE_SPLIT && this.splitDir == dir && pFirst.getMiddle(dir).equals(this.splitLine)) {
    if (pFirst.start[dir].equals(this.splitEnd)) {
      this.splitEnd = pLast.end[dir];
    } else if (pLast.end[dir].equals(this.splitStart)) {
      this.splitStart = pFirst.start[dir];
    } else {
      this.message = "This long split is not adjacent to the previous split";
      return;
    }
    var res = this.board.longSplit(pFirst, pLast, dir);
    if (res.length == 0) {
      this.message = "Failed to do long split"
      return;
    }
    this._addToSwappablePieces(res);
    this.message = "";
  } else {
    this.message = "The piece is not a part of long split";
  }
}


Move.prototype.merge = function(pLeftTop, pRightTop, pLeftBottom, pRightBottom) {
  if (this.validator.isEnabled()) {
	  if (pLeftTop.color != this.color) {
	    this.message = "You can't merge your opponent's pieces";
	    return;
	  }
	  if (this.state != STATE_CLEAR) {
	    this.message = "Can not merge. Already splitting";
	    return;
	  }
  }
  if (!this.board.canMerge(pLeftTop, pRightTop, pLeftBottom, pRightBottom)) {
    this.message = "The pieces can not be merged. Check size proportions, alignment and colors";
    return;
  }
  this.mergeLeftTop = pLeftTop;
  this.mergeRightTop = pRightTop;
  this.mergeLeftBottom = pLeftBottom;
  this.mergeRightBottom = pRightBottom;
  if (!this.validator.isEnabled()) {
    this.board.merge(pLeftTop, pRightTop, pLeftBottom, pRightBottom);
    return;
  }
  this.state = STATE_MERGE;
  this._addToSwappablePieces(this.board.merge(pLeftTop, pRightTop, pLeftBottom, pRightBottom));
  this.message = "";
}

Move.prototype.swap = function(piece) {
  if (!this.validator.isEnabled()) {
    piece.swap();
    this.message = "";
    return true;
  }
  if (this.capturedAtSwap) {
    this.message = "Can not swap. Your piece was captured. Cancel move and try again";
    return false;
  }
  if (this.state == STATE_CLEAR) {
    this.message = "You need to split or merge before you swap";
    return false;
  }
  for (var i = this.numSwappedPieces-1; i > 0; i--) {
    if (this.swappedPieces[i] == piece && !this._swappable(piece)) {
      // revert everything starting this one
      this.board.resetCapturedPieces(i);
      for (var j = i+1; j < this.numSwappedPieces; j++) {
        var foundBefore = false;
        for (var k = 0; k < i; k++) {
          if (this.swappedPieces[k] == this.swappedPieces[j]) {
            foundBefore = true;
            break;
          }
        }
        if (!foundBefore) { 
          this.swappedPieces[j].swapped = false;
        }
      }
      if (this.numSwappedPieces -1 != i) {
        this.swappedPieces[this.numSwappedPieces-1].swap();
        this.swappedPieces[i].swap();
      }
      this.numSwappedPieces = i+1;
      this.message = "";
      return true;
    }      
  }
  if (Board.prototype._findPiece(this.swappablePieces, piece) && !this._swappable(piece)) {
    for (var j = 1; j < this.numSwappedPieces; j++) {
      this.swappedPieces[j].swapped = false;
    }
    this.message = "";
    this.board.resetCapturedPieces(0);
      
    if (piece.swapped) {
      if (this.numSwappedPieces > 1) {
        this.swappedPieces[this.numSwappedPieces-1].swap();
      }

      this.swappedPieces = new Array();
      this.numSwappedPieces = 0;
      piece.swapped = false;
      piece.color = this.color;
    } else {
      if (this.numSwappedPieces > 0) {
        
	      this.swappedPieces[0].color = this.color;
	      this.swappedPieces[0].swapped = false;
	      if (this.numSwappedPieces > 1 && this.swappedPieces[this.numSwappedPieces-1] != this.swappedPieces[0]) {
	        this.swappedPieces[this.numSwappedPieces-1].swap();																
          }
          this.swappedPieces = new Array();
      }
      piece.swapped = true;
      piece.swap();
      this.swappedPieces[0] = piece;
      this.numSwappedPieces = 1;
    }
    return true;
  } else if (this.numSwappedPieces == 0) {
    this.message = "You need to start swap with the pieces you split or merged";
    return false;
  }
  if (this._swappable(piece)) {
    if (this.numSwappedPieces > 1) {
      this.swappedPieces[this.numSwappedPieces-1].swap();
    }
    if (this.board.isPieceCaptured(piece, OPPOSITE_COLOR[this.color])) {
      //this.swappedPieces[this.numSwappedPieces-1].swap(); // swap back
      this.message = "Your piece is captured during swap";
      this.capturedAtSwap = true;
      piece.captured = true;
      piece.swap();
      return true;
    }
    piece.swapped = true;
    piece.swap();
    this.message = "";
    this.numSwappedPieces +=1;
    this.swappedPieces[this.numSwappedPieces -1] = piece;
    this.board.evaluate();
    this.board.captureIsolatedPieces(false, this.numSwappedPieces);
    return true;
  }
}
Move.prototype.complete = function() {
  if (this.winningColor != NULL_COLOR) {
    return true; // resigned
  }
  if (this.validator.isEnabled() && this.state == STATE_CLEAR) {
    this.message = "The move is empty";
    return false;
  }
  if (this.validator.isEnabled() && this.numSwappedPieces == 1) {
    this.message = "The swap is incomplete";
    return false;
  }
  
  this.board.evaluate();
  this.winningColor = this.board.getWinningColor();
  if (this.winningColor != NULL_COLOR) {
    this.message = COLOR_TEXT[this.winningColor] + " has won!";
  }
  if (this.validator.isEnabled()) {
    this.board.captureIsolatedPieces(true);
  }
  return true;
}

Move.prototype.setDemoMode = function(isDemo) {
}

Move.prototype._swappable = function(piece) {
  if (piece.color == this.color) {
    this.message = "Only " + COLOR_TEXT[OPPOSITE_COLOR[this.color]] + " can be swapped";
    return false;
  }
  if (piece.isolated) {
    this.message = "This piece is already captured by you, can't swap.";
    return false;
  }
  var p = this.swappedPieces[this.numSwappedPieces -1];
  if (Board.prototype.aligned(piece, this.swappedPieces[this.numSwappedPieces-1])) {
    return true;
  }
  this.message = "This piece is not properly aligned with the previously swapped piece";
  return false;
}


Move.prototype._addToSwappablePieces = function(pieces) {
  for (var i = 0; i < pieces.length; i++) {
    this.swappablePieces.push(pieces[i]);
    pieces[i].swappable = true;
  }
}

toTest.push(Move);


Move.prototype.test = function() {
}