

/*****************************************************************************
 *
 *  Define the Round Object and Functions
 *
 *****************************************************************************/
function Round(allPlayers)
{
    this.locked = true;
    this.rows = new Array();
    this.players = allPlayers;

    // place draw pile
    moveDiv('cardback', 110, 330, 'anchor', true);
    moveDiv('cardsleft', 115, 365, 'anchor', true);

    // place the chart
    moveDiv('chart', 65, 330, 'anchor', true);

    this.humanPlayer = this.getHumanPlayer();
    this.turnCard = false;

    for (var i=0; i<this.players.length; i++)
    {
        this.players[i].startNewRound();
    }


    this.drawPile = this.newDeck();
    this.pendingCard = null;

    this.handCount = 0;

    // choose a random player
    this.currentPlayer = Math.floor(Math.random()*157) % allPlayers.length;

}

Round.prototype.getRows = function()
{
    return this.rows;
}

Round.prototype.getPendingCard = function()
{
    return this.pendingCard;
}

Round.prototype.getNumCardsLeft = function()
{
    return this.drawPile.length;
}

Round.prototype.getStandings = function()
{
    var tplayers = new Array();
    for (var i=0; i<this.players.length; i++)
    {
        var theScore = this.players[i].calculateCurrentScore();
        tplayers[i] = { score: theScore, player: this.players[i] };
    }

    tplayers.sort(this.sortStandings);
    return tplayers;

}



Round.prototype.getHumanPlayer = function()
{
    for (var i=0; i<this.players.length; i++)
    {
        if (!this.players[i].isComputerPlayer())
        {
            return this.players[i];
        }
    }
    return null;
}

Round.prototype.getCurrentPlayer = function()
{
    return this.players[this.currentPlayer];
}

// only call if you know there is a row card available
Round.prototype.advanceToNextPlayer = function()
{
    this.currentPlayer = (this.currentPlayer + 1) % this.players.length;
    while (this.getCurrentPlayer().getHasRow())
    {
        this.currentPlayer = (this.currentPlayer + 1) % this.players.length;
    }
}


Round.prototype.newDeck = function()
{
    var cards = new Array();

    // populate deck
    for (var i=1; i<10; i++)
    {
        cards.push(new Card('blue', i));
        cards.push(new Card('red', i));
        cards.push(new Card('pink', i));
        cards.push(new Card('green', i));
        cards.push(new Card('yellow', i));
        cards.push(new Card('brown', i));

        if (this.players.length > 3)
        {
            cards.push(new Card('gray', i));
        }
    }

    // assign players their initial card
    var chosenCards = new Array();
    while (chosenCards.length != this.players.length)
    {
        // choose a card at random
        var rand = Math.floor(Math.random()*15793) % cards.length;
        var candidate = cards[rand];

        // if candidate color in chosen cards already then
        // reject it
        for (var i=0; (i<chosenCards.length) && (candidate != null); i++)
        {
            if (candidate.getColor() == chosenCards[i].getColor())
            {
                candidate = null;
            }
        }
        if (candidate != null)
        {
            chosenCards.push(candidate);
            cards.splice(rand, 1);
        }
    }

    // add the cards to the players hand
    for (var i=0;i<this.players.length; i++)
    {
        this.players[i].addCard(chosenCards[i]);
    }

    // push in the wilds and the plus 2s
    cards.push(new Card('wild', 1));
    cards.push(new Card('wild', 2));
    cards.push(new Card('wild', 3));

    for (var i=1; i<=10; i++)
    {
        cards.push(new Card('plus2', i));
    }

    // shuffle
    var deck = this.shuffleDeck(cards);

    // insert turn card as the 16th from the last card
    deck.splice(deck.length-15,0,new Card('turn'));

    return deck;
}

Round.prototype.shuffleDeck = function(deck)
{
    var cards = new Array();

    while (deck.length > 0)
    {
        var rand = Math.floor(Math.random()*15791) % deck.length;
        if (deck.length == 1)
        {
            rand = 0;
        }
        cards.push((deck.splice(rand, 1))[0]);
    }

    return cards;
}

Round.prototype.getPlayers = function()
{
    return this.players;
}



Round.prototype.start = function()
{
    this.startNewHand();
}


Round.prototype.startNewHand = function()
{
    this.rows = new Array();

    callback = new AsyncCallback("round.takeTurn();", this.players.length);

    // add Row cards
    for (var i=1; i<= this.players.length; i++)
    {
        this.players[i-1].startNewHand();

        var rowCard = new Card('row', i);
        this.rows.push(new Array());
        this.rows[i-1].push(rowCard);
        this.flyRow(rowCard);
    }

    this.handCount++;
}

Round.prototype.lockUI = function(b)
{
    this.locked = b;
}

Round.prototype.takeTurn = function()
{
    this.lockUI(true);
    var player = this.getCurrentPlayer();

    callback = new AsyncCallback("round._takeTurn();", 1);
    player.activate();
}

Round.prototype._takeTurn = function()
{
    var player = this.getCurrentPlayer();

    if (player.isComputerPlayer())
    {
        player.takeTurn(this);
    }
    else
    {
        // let human run the show manually
        this.lockUI(false);
    }
}

Round.prototype.deckClick = function()
{
    //if (!this.getCurrentPlayer().isComputerPlayer())
    if (!this.locked)
    {
        return this._deckClick();
    }
}


Round.prototype._deckClick = function()
{
    if (this.pendingCard != null)
    {
        alert("Click a Row Card to place the new card");
        return;
    }

    // It's always okay to take a card when at least one row has less than 3 cards
    // The actual limit is 4 since the 'row' card itself is already in the row
    var lowRow = false;
    for (var i=0; (i<this.rows.length) && !lowRow; i++)
    {
        if ((this.rows[i] != null) && (this.rows[i].length < 4))
        {
            lowRow = true;
        }
    }

    if (lowRow)
    {
        // expose the next card in the deck and make it the pending card
        var card = this.drawPile.shift();

        if (card.getColor() == 'turn')
        {
            // show the turn card and pick the next card
            moveDiv('turn', 65, 270, 'anchor', true);

            this._deckClick();
            this.turnCard = true;
        }
        else
        {
            // the card always gets assigned the highest z-order so far
            this.showCard(card);
            this.pendingCard = card;



            if (this.drawPile.length == 0)
            {
                moveDiv('cardback', 110, 330, 'anchor', false);
                moveDiv('cardsleft', 110, 325, 'anchor', false);
            }
        }

        var cardsLeft = this.drawPile.length;
        if (!this.turnCard)
        {
            // compensate for the turn card
            cardsLeft -= 1;
        }
        document.getElementById('cardsleft').innerHTML =
            "<span style='color:yellow'><b>(" + cardsLeft +
            ')</b></span>';

    }
    else
    {
        alert("All rows are full so you must take a row");
    }
}

Round.prototype.showCard = function(card, isVisible)
{
    if (isVisible == null)
    {
        isVisible = true;
    }
    moveDiv(card.getDivId(), 110, 270, 'anchor', isVisible, this.zorder);
    this.zorder++;
}

Round.prototype.rowClick = function(theRow)
{
    //if (!this.getCurrentPlayer().isComputerPlayer())
    if (!this.locked)
    {
        return this._rowClick(theRow);
    }
}

Round.prototype._rowClick = function(theRow)
{
    if (this.pendingCard != null)
    {
        // placing the pending card
        var row = this.rows[theRow - 1];
        if (row.length < 4)
        {
            row.push(this.pendingCard);

            // don't advance to the next player until the card movement is done

            callback = new AsyncCallback("round.takeTurn();", 1);
            this.flyRowCard(this.pendingCard, theRow, row.length);
            this.pendingCard = null;

            // advance to the next player without a row card
            this.advanceToNextPlayer();
        }
        else
        {
            alert("That row already has 3 cards in it.");
        }
    }
    else
    {
        var row = this.rows[theRow-1];

        if ((row == null) || (row.length == 1))
        {
            alert("There must be at least one card in the row to take it");
            return;
        }

        // taking the row
        var player = this.getCurrentPlayer();
        var rowCard = row[0];

        //alert("Giving " + player.getName() + " the row cards");

        // iterate through the cards in the row and give them to the current player
        callback = new AsyncCallback("round._finishRowClick(" + theRow + ");", row.length);
        for (var i=0; i<row.length; i++)
        {
            player.addCard(row[i]);
        }
    }
}


Round.prototype._finishRowClick = function(theRow)
{
    // This row is empty now
    this.rows[theRow-1] = null;

    // check for final row being taken
    var rowCnt = this.getRowsLeft();

    if (rowCnt == 0)
    {
        // if the turn card is exposed, then this round is over.
        if (this.turnCard)
        {
            // the round is done. Computer final scores for the round
            hideDivById('castle');
            hideDivById('turn');
            this.computeRoundScores();
        }
        else
        {
            // just the hand is over so reset for the next hand in
            // this round
            round.startNewHand(false);
        }
    }
    else
    {
        // advance to the next player without a row card
        this.advanceToNextPlayer();
        round.takeTurn();
    }
}

Round.prototype.computeRoundScores = function()
{
    var byscore = this.players.slice();

    for (var i=0; i<this.players.length; i++)
    {
        this.players[i].computeRoundScores();
    }

    byscore.sort(this.sortByScore);

    var buf = '<ol>';
    for (var i=0; i<byscore.length; i++)
    {
        buf += '<li>' + byscore[i].getName() +
                ' (' + byscore[i].getScore() + ')';
    }
    buf += '</ol>';

    var resultsDivId = 'roundend';
    moveDiv('deckscore', 36, 210, 'anchor', true, 1000);
    if (game.getRoundsLeftCount() <= 0)
    {
        // show round result in "roundend" div.
        document.getElementById('gameresults').innerHTML = buf;
        resultsDivId = 'gameend';
    }
    else
    {
        // show round result in "roundend" div.
        document.getElementById('roundresults').innerHTML = buf;
    }
    moveDiv(resultsDivId, 45, 250, 'anchor', true, 1000);
}

Round.prototype.getRowsLeft = function()
{
    var cnt = this.rows.length;
    for (var i=0; i<this.rows.length; i++)
    {
        if ((this.rows[i] == null) || (this.rows[i].length == 0))
        {
            cnt--;
        }
    }
    return cnt;
}

Round.prototype.flyRow = function(card)
{
    switch (card.getIndex())
    {
        case 1:
            flyCard(card, 160, 330, 'anchor', 50, false);
            break;
        case 2:
            flyCard(card, 160, 270, 'anchor', 50, false);
            break;
        case 3:
            flyCard(card, 160, 390, 'anchor', 50, false);
            break;
        case 4:
            flyCard(card, 160, 210, 'anchor', 50, false);
            break;
        case 5:
            flyCard(card, 160, 450, 'anchor', 50, false);
            break;
    }
}

Round.prototype.flyRowCard = function(card, theRow, theRowLength)
{
    var xoffset = 40 * (theRowLength-1);

    switch (theRow)
    {
        case 1:
            flyCard(card, xoffset, 0, 'row1', 50, false);
            break;
        case 2:
            flyCard(card, xoffset, 0, 'row2', 50, false);
            break;
        case 3:
            flyCard(card, xoffset, 0, 'row3', 50, false);
            break;
        case 4:
            flyCard(card, xoffset, 0, 'row4', 50, false);
            break;
        case 5:
            flyCard(card, xoffset, 0, 'row5', 50, false);
            break;
    }
}



Round.prototype.sortByScore = function(p1, p2)
{
    if (p1 == null)
    {
        return 1;
    }

    if (p2 == null)
    {
        return -1;
    }

    return p2.getScore() - p1.getScore();
}


Round.prototype.sortStandings = function(p1, p2)
{
    if (p1 == null)
    {
        return 1;
    }

    if (p2 == null)
    {
        return -1;
    }

    return p2.score - p1.score;
}



// ANALYSIS METHODS



// returns how many cards of a color are in other player's hands
Round.prototype.getColorCount = function(theColor, thePlayer)
{
    var cnt = 0;
    for (var i=0; i<this.players.length; i++)
    {
        if (this.players[i] != thePlayer)
        {
            cnt += this.players[i].getHand().getColorCount(theColor);
        }
    }
    return cnt;
}

// returns who is collecting a specified color.
Round.prototype.getCollectorCount = function(theColor, thePlayer)
{
    var cnt = 0;
    for (var i=0; i<this.players.length; i++)
    {
        if ((this.players[i] != thePlayer) &&
            (this.players[i].getHand().getColorCount(theColor) > 0))
        {
            cnt++;
        }
    }
    return cnt;
}
