/* Object representing a player of the game.
 * @param gameboard reference back to the gameboard this is a part of.
 * @param target the UI element that this player represents.
 * @param fills an array of the peices this drops when moving off spaces.
 */
function Player(gameboard, target, fills) {
    this.gameboard = gameboard;
    this.target = target;
    this.fills = fills;
    
    ++this.gameboard.movingPlayers;
}

Player.prototype.isActivated = false;
Player.prototype.isAutoPlayer = false;
Player.prototype.score = 0;
Player.prototype.canMove = true;
Player.prototype.totalAnimationSteps = 0;

/* Add some points to the score of this char */
Player.prototype.addScore = function(value) {
    this.score += value;
    // Calls back to the gameboard.
    this.scoreCallback(value);
}

/* Place the player over the specified tile
 * @param x,y the coordinates of the tile to move to.
 */
Player.prototype.setPosition = function(x, y) {
    this.x = x;
    this.y = y;
    
    if (y % 2 == 0)
        this.target.setValue("canvas.Left", x * 96);
    else
        this.target.setValue("canvas.Left". x * 96 + 50);
        
    // Account for the height of the tile
    var hex = this.getCurrentHex();
    var height = hex.value - 1;
    height *= 12;
        
    this.target.setValue("canvas.Top", y * 76 - height + 20);
    
    hex.occupier = this;
}

/* Animates the player to the specified tile (as opposed to just moving it to there)
 * @param x,y the coordinates of the tile to move to.
 */
Player.prototype.animatePlayerTo = function(x, y) {
    this.x = x;
    this.y = y;
    
    var finalX = x * 96;
    if (y % 2 == 1)
        finalX += 50;
    
        
    var hex = this.getCurrentHex();
    var height = hex.value - 1;
    height *= 12;
    
    var finalY = y * 76 - height + 20;
    
    this.animateTo(finalX, finalY);
    
    hex.occupier = this;
}

/* Get the hex this is currently over. */
Player.prototype.getCurrentHex = function() {
    return this.gameboard.hexes[this.x][this.y];
}

/* Make this player the active player. 
 * If this player is a computer-controlled player, then this will run the
 * strategy to find the next move, then take it.
 */
Player.prototype.activate = function() {
    if (!this.isActivated) {
        // Show the marker that this is the active player
        var marker = this.gameboard.control.content.createFromXaml(this.gameboard.markerXaml);
        var hex = this.getCurrentHex();
        
        hex.target.children.add(marker);
        
        marker.setValue("canvas.Top", (hex.value - 1) * -12);
        
        this.isActivated = true;
        
        // Run the logic to auto play if needed.
        if (this.isAutoPlayer)
            this.autoPlay();
        // Check if this player can actually move, if not, lose.
        else if (this.dumbFindBestPlay() == null) {
            this.setOverDeveloped();
            this.gameboard.nextPlayer();
        }
    }
}

/* Called when this players turn is over. */
Player.prototype.deactivate = function() {
    if (this.isActivated) {    
        var hex = this.getCurrentHex();
        hex.target.children.removeAt(hex.target.children.count - 1);
        
        this.isActivated = false;
        
        hex.setFill(this.fills[hex.value - 1]);
    }
}

/* Runs all the logic needed to find the next move.
 * Used for the computer controlled players.
 */
Player.prototype.autoPlay = function() {
    if (!this.canMove) {
        this.gameboard.nextPlayer();
        return;
    }
    
    var currentHex = this.getCurrentHex();
    var topHex = this.findBestPlay();

    if (topHex != null)
        this.gameboard.tryMoveTo(topHex);
    else {
        this.setOverDeveloped();
        this.gameboard.nextPlayer();
    }
}

/* Oh noes! we ran out of room!
 * Called when the player can no longer move.
 */
Player.prototype.setOverDeveloped = function() {
    if (this.canMove) {
        this.canMove = false;
        this.gameboard.decrementMovingPlayers();
        if (this.isAutoPlayer)
            this.target.opacity = 0;
    }
}

/* Find the next best play, this is the standard Suit strategy.
 */
Player.prototype.dynamicFindBestPlay = function() {
    var maxRadius = 10;
    var depth = 2;
    
    if (this.gameboard.openSpaces < 70) {
        maxRadius = 7;
        depth = 1;
    }
    if (this.gameboard.openSpaces < 65) {
        depth = 2;
        maxRadius = 5;
    }
    if (this.gameboard.openSpaces < 50) {
        depth = 2;
        maxRadius = 5;
    }
    
    return this.getBestPlay(maxRadius, depth);
}

/* Find the next best play using more logic, but looking less distance.
 * This is the default Techy strategy.
 */
Player.prototype.timidFindBestPlay = function() {
    var maxRadius = 3;
    var depth = 2;
    
    return this.getBestPlay(maxRadius, depth);
}

Player.prototype.dumbFindBestPlay = function() {
    var maxRadius = 1;
    var depth = 0;
    
    return this.getBestPlay(maxRadius, depth);
}

// Default player strategy to the dynamic version.
Player.prototype.findBestPlay = Player.prototype.dynamicFindBestPlay;

/* Find the best play, using a really really really bad algorithm.
 * This algorithm is here until Janete implements her uber min/max algorithm for me,
 * but it was able to beat her 3 times in a row :)
 * @param maxRadius max distance to look for a good spot.
 * @param depth amount of look ahead to use when considering what a good spot is.
 */
Player.prototype.getBestPlay = function(maxRadius, depth) {
    var topHex = null;
    var currentHex = this.getCurrentHex();
    var topFullValue = -1;
    var topValue = -1;
    var player = this;
    
    var playFinder = function(hex) {
        if (player.gameboard.canMoveTo(hex, player, currentHex)) {
            var value = Math.pow(hex.value, depth + 1);
            if (depth > 0)
                value = player.findHexValue(hex, maxRadius, depth - 1);
                
            if (value >= topFullValue) {
                topFullValue = value;
                topValue = hex.value;
                topHex = hex;
            }
            return true;
        }
        return false;
    }
    
    this.gameboard.walkPossibilities(currentHex, maxRadius, playFinder);
    
    return topHex;
}

/* Uses lame logic to determine how good a specific hex is to move to.
 * Takes into consideration the value of the hexes around this one.
 */
Player.prototype.findHexValue = function(base, maxRadius, depth) {
    var value = base.value;
    var player = this;
    
    var valueFinder = function(hex) {
        if (player.gameboard.canMoveTo(hex, player, base)) {
            value += hex.value;
            if (depth > 1) {
                value += player.findHexValue(hex, maxRadius, depth - 1);
            }
            return true;
        }
        return false;
    }
    
    this.gameboard.walkPossibilities(base, maxRadius, valueFinder);
    
    return value;
}

/* Per frame callback when animating this character to another tile. */
Player.prototype.handleAnimationUpdate = function() {
    ++this.animationStep;
    if (this.animationStep <= this.totalAnimationSteps) {
    
        var delta = this.animationStep / this.totalAnimationSteps;
        this.target.setValue("canvas.Left", (this.destinationX - this.startX) * delta + this.startX);
        this.target.setValue("canvas.Top", (this.destinationY - this.startY) * delta + this.startY);
    }
        
    if (this.animationStep > this.totalAnimationSteps + 1)
        this.stopAnimation();
}

/* Starts the animation to the specific position on the board.
 * @param x,y coordinates (in pts) of where to move to.
 */
Player.prototype.animateTo = function(x, y) {
    this.startX = this.target.getValue("canvas.Left");
    this.startY = this.target.getValue("canvas.Top");
    this.destinationX = x;
    this.destinationY = y;
    
    var deltaX = this.destinationX - this.startX;
    var deltaY = this.destinationY - this.startY;
    var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
    var totalSteps = Math.round(distance / 10);
    this.totalAnimationSteps = totalSteps;
    this.animationStep = 0;
    
    this.gameboard.startAnimation(this);
}

/* Stop this character from moving. */
Player.prototype.stopAnimation = function() {
    this.animationStep = 0;
    this.totalAnimationSteps = 0;
    
    this.gameboard.stopAnimation(this);
    this.gameboard.nextPlayer();
}

/* Checks to see if this character is animating,
 * used to prevent certain actions after the next play choice has been
 * committed, but the player has not changed.
 */
Player.prototype.isAnimating = function() {
    return this.totalAnimationSteps != 0;
}