

var actions = new Array();
function Action( code, arg )
{
    this.code = code;
    this.arg = arg;
    this.millisec = -1;
    this.fromUsername = null;
    this.actionID = -1;    // only REAL-TIME actions get a Seq ID.
}
var _completedAction = -1;
var _currentlyPlayingAction = -1;

Action.prototype.Play = function()
{
    switch( this.code )
    {
        case "joinGame":    // another user has joined the game you are already in.
            if (Player.Exists(this.fromUsername))  // must check to see if already exists, because sometimes we can get a late message.
                break;
            Player.Create( this.fromUsername ).Init();
            break;
        case "startGame":   // the creator has started the game.
            Player.StartGame();
            break;
        case "iLeft":
            Player.Get( this.fromUsername ).LeftGame( "Left" );
            break;
        case "iLagged":
            Player.Get( this.fromUsername ).LeftGame( "Lagged" );
            break;

        case "typeFocus":
            var chatWindow = this.GetChatWindow(true);
            gainedFocus( chatWindow, (this.fromUsername!=null) );
            if ( Player.IsMyTurn() )
                trayCell.style.borderWidth = "0px";
            break;
        case "typeBlur":
            var chatWindow = this.GetChatWindow(false);
            lostFocus( chatWindow );
            if ( Player.IsMyTurn() )
            {
                trayCell.style.borderWidth = "2px";
                trayCell.style.borderStyle = "dashed";
            }
            break;
        case "type":
            var chatWindow = this.GetChatWindow(true);
            typeCharacter( chatWindow, this.arg );
            break;
        case "backspace":
            var chatWindow = this.GetChatWindow(true);
            pressBackspace( chatWindow );
            break;
        case "moveBack":
            var chatWindow = this.GetChatWindow(true);
            moveBack( chatWindow );
            break;
        case "moveForward":
            var chatWindow = this.GetChatWindow(true);
            moveForward( chatWindow );
            break;

        case "left":
            Board.SetCursor( Board.NextLeft(), Board.CursorRow() );
            break;
        case "right":
            Board.SetCursor( Board.NextRight(), Board.CursorRow() );
            break;
        case "up":
            Board.SetCursor( Board.CursorCol(), Board.NextUp() );
            break;
        case "down":
            Board.SetCursor( Board.CursorCol(), Board.NextDown() );
            break;

        case "laid":
            var tile = scrabbleSet[ parseInt(this.arg) ];
            tile.ShowImg();
            tile.SetPosition(boardCursor);

            // Is there already a tile on that col/row?
            var pt = tile.GetPosition();
            for (var inx = 0; inx < tileLaidDown.length; inx++)
            {
                var existingTile = tileLaidDown[inx];
                if ( existingTile.GetPosition().Equals( pt ) )
                {
                    this.RemoveTile( existingTile );
                    tileLaidDown = list_removeAtIndex( tileLaidDown, inx );
                    break;
                }
            }

            tileLaidDown.push( tile );
            break;

        case "wildcardPick":
            var tile = tileLaidDown[ tileLaidDown.length-1 ];
            tile.letter = this.arg.toLowerCase();
            
            tile.letterDIV = AddNode( document.body, "DIV" );
            tile.letterDIV.style.color = "red";
            tile.letterDIV.style.fontSize = "18pt";
            tile.letterDIV.style.position = "absolute";

            tile.letterDIV.style.top = addPixels( tile.imgNode.style.top, 3 );
            tile.letterDIV.style.left = addPixels( tile.imgNode.style.left, 6 );
            
            tile.letterDIV.innerHTML = this.arg;
            break;

        case "beginExchange":
            exchangeMode = true;
            exchangeCell.style.color = "black";
            exchangeCell.style.borderWidth = "2px";
            exchangeCell.style.borderStyle = "dashed";
            trayCell.style.borderWidth = "0px";
            trayCell.style.borderStyle = "dashed";
            break;

        case "exchange":
            if ( this.fromUsername )
                tileExchanging.push(null); // just to count the number of tiles the other player is exchanging (cannot see what tiles).
            currentPlayer.ShowMessage( "Exchanging "+tileExchanging.length+" tiles..." );
            break;

        case "esc":
            if ( exchangeMode )
            {
                if ( tileExchanging.length == 0 )
                {
                    currentPlayer.ShowMessage( "" );
                    exchangeMode = false;
                    exchangeCell.style.color = "gray";
                    exchangeCell.style.borderWidth = "0px";
                    trayCell.style.borderWidth = "2px";
                    break;
                }

                if ( this.fromUsername )
                    tileExchanging.pop();
                currentPlayer.ShowMessage( "Exchanging "+tileExchanging.length+" tiles..." );
            }
            else
            {
                var lastPlayedTile = tileLaidDown.pop();
                if (!lastPlayedTile)
                    break;

                if (lastPlayedTile.letterDIV)
                {
                    document.body.removeChild( lastPlayedTile.letterDIV );
                    delete lastPlayedTile.letterDIV;
                    lastPlayedTile.letter = " ";
                }
                this.RemoveTile( lastPlayedTile );
            }
            break;


        case "doneWithTurn":        // commit laid down tiles, or exchange, or just a pass
            if ( exchangeMode && tileExchanging.length > 0 )
            {
                currentPlayer.ShowMessage( "Exchanged "+tileExchanging.length+" tiles." );

                if ( Player.IsMyTurn() )
                {
                    var request = "";
                    for (var inx = 0; inx < tileExchanging.length; inx++)
                    {
                        var trayTD = tileExchanging[inx];
                        var tile = TrayTile(trayTD);
                        tile.HideImg();

                        if (inx > 0)
                            request += " ";
                        request += tile.scrabbleSetInx;
                    }
                    CallbackBusEx("exchangeFromBag", request, function(txt)
                    {
                        if (txt.length == 0)
                        {
                            alert("No tiles left in the bag to exchange.");
                            tileExchanging = [];
                            return;
                        }

                        var newTileInxs = txt.split(/\n/);
                        for (var inx = 0; inx < newTileInxs.length; inx++)
                        {
                            var trayTD = tileExchanging[inx];
                            trayTD.tileInx = newTileInxs[inx];
                            var tile = TrayTile(trayTD);
                            tile.SetPosition(trayTD);
                            tile.ShowImg();
                        }

                        if (tileExchanging.length != newTileInxs.length)
                            alert("Only "+newTileInxs.length+" tiles left in the bag to exchange.");

                        tileExchanging = [];
                    });
                }
                else
                    tileExchanging = [];

                exchangeMode = false;
                exchangeCell.style.color = "gray";
                exchangeCell.style.borderWidth = "0px";
                trayCell.style.borderWidth = "2px";

                passedTurnCount = 0;
                scorelessTurnCount++;
                currentPlayer.EndTurn();
            }
            else if ( tileLaidDown.length > 0 )
            {
                var words = Board.GetWords( tileLaidDown );
                if ( words == null )
                {
                    if ( this.fromUsername == null )
                        alert("Must be adjacent to existing letters.");
                    break;
                }
                passedTurnCount = 0;
                Challenge.TilesLaidDown(words);
            }
            else
            {
                scorelessTurnCount++;
                passedTurnCount++;
                currentPlayer.ShowMessage( "Passed." );
                currentPlayer.EndTurn();
            }

            break;


        case "challengeChoice":
            _challengeObject.ChallengeChoice( this.fromUsername?this.fromUsername:whoAmI.name, this.arg );
            break;

        case "challengeOutcome":
            _challengeObject.ChallengeOutcome( this.arg );
            break;

        default:
            debugger;
            break;
    }

    if ( this.actionID > -1 )
        _completedAction = this.actionID;
}
var scorelessTurnCount = 0;
var passedTurnCount = 0;






Action.prototype.RemoveTile = function( tile ) // from board, put back to tray
{
    if (this.fromUsername)
        tile.HideImg();
    else
    {
        var inx;
        for (inx = 0; inx < 7; inx++)
        {
            var td = trayTable.rows[0].cells[inx];
            if ( !TrayFilled(td) )
            {
                tile.SetPosition( td );
                td.tileInx = tile.scrabbleSetInx;
                break;
            }
        }
    }
}
Action.UndoAllTiles = function()
{
    while ( tileLaidDown.length > 0 )
    {
        var lastPlayedTile = tileLaidDown.pop();
        if (!lastPlayedTile)
            continue;

        if (lastPlayedTile.letterDIV)
        {
            document.body.removeChild( lastPlayedTile.letterDIV );
            delete lastPlayedTile.letterDIV;
            lastPlayedTile.letter = " ";
        }
        
        if ( Player.IsMyTurn() )
        {
            var inx;
            for (inx = 0; inx < 7; inx++)
            {
                var td = trayTable.rows[0].cells[inx];
                if ( !TrayFilled(td) )
                {
                    lastPlayedTile.SetPosition( td );
                    td.tileInx = lastPlayedTile.scrabbleSetInx;
                    break;
                }
            }
        }
        else
            lastPlayedTile.HideImg();
    }
}



Action.prototype.GetChatWindow = function( flash )
{
    var chatWindow;
    if (this.fromUsername)
    {
        var player = Player.Get( this.fromUsername );
        chatWindow = player.chatWindow;

        if (flash && otherPlayerChatMenu.currentTab !== player.tab)
            otherPlayerChatMenu.FlashTab( player.tab.inx );
    }
    else
        chatWindow = whoAmI.chatWindow;

    return chatWindow;
}


Action.prototype.Text = function()
{
    return this.code+"^"+this.millisec+"^"+this.arg;
}
Action.FromText = function( txt )
{
    var array = txt.split(/\^/);
    var code = array[0];
    var millisec = parseInt(array[1]);
    var username = array[2];
    var arg = null;
    if (array.length == 4)
        arg = array[3];
    else if (array.length > 4)
        arg = "^";
    var a = new Action( code, arg );
    a.millisec = millisec;
    a.fromUsername = username;
    return a;
}

Action.Add = function( code, arg )
{
    var a = new Action( code, arg );
    a.Play( true );

    if ( IsConnected() )
    {
        if ( lastSendDate == null )
            lastSendDate = new Date();

        a.millisec = (new Date()).valueOf() - lastSendDate.valueOf();
        actions.push( a );
    }
}

var lastSendDate;


