
 // Michael McElroy
 // michaelmcelroy.net, 2010
 
 // note: All times are in milliseconds.
 // note: When castling, the rook's move is stored in the moves array (after the king's move), but it is not transmitted to the server.


 // constants

    var YES = true;
    var NO = false;
    var ALL = YES;
    var ANIMATE = YES;
    var INTEGER = YES;
    var TRACE_AJAX = NO;
    var SETTLE_FACTOR = 0.60;
    var LONG_SETTLE_DELAY = 128;
    var SHORT_SETTLE_DELAY = 32;
    var LONG_RENDER_DELAY = 128;
    var SHORT_RENDER_DELAY = 32;
    var AJAX_DELAY = 512;
    var TIMEOUT_THRESHOLD = 1000 * 60 * 2;
    var EMAIL_ADDRESS = "ch~e-ss@michaelmcelroy.net";
    var EMAIL_ADDRESS_DETENTS = "-~";


 // independent variables

    var game = null;
    var view = null;
    var ajax = null;
    var ai = null;


 // dependent variables

    var $ = function (id)
    
        {
        return (window . document . getElementById (id));
        };

    var is_integer = function (value)
    
        {
        var integer = NO;
        
        if (value != null) integer = value == Math . floor (value);

        return (integer);
        };  
    
    var get_time_stamp = function ()
    
        {
        var date = new Date ();
        
        return (date . getTime ());
        };
    
    var get_copy = function (data)
    
        {
        var copy = null;
        
        if (data != null)
        
            {
            copy = new Array ();
            
            for (var d = 0; d < data . length; d ++) copy . push (data [d]);
            }
        
        return (copy);
        };

    var get_url_value = function (key)
    
        {
        var value = null;
        var pairs = window . location . search . substring (1) . split ("&");
        
        for (var p = 0; p < pairs . length; p ++)
        
            {
            var pair = pairs [p] . split ("=");
            
            if (pair [0] == key)
            
                {
                value = pair [1];
                
                break;
                }
            }

        return (value);
        };
        
    var get_email_address = function ()
    
        {
        return (EMAIL_ADDRESS . replace (new RegExp ("[" + EMAIL_ADDRESS_DETENTS + "]", "g"), ""));
        };


 // methods

    var initialize = function ()
    
        {
        ajax = new mm_ajax ();
        ajax . initialize ();

        game = new mm_game ();
        game . initialize ();

        view = new mm_view ();
        view . initialize ();
        
        ai = new mm_ai ();
        ai . initialize ();
        
        attach_event_listeners ();
        
        window . onbeforeunload = game . finalize_cb;

        $ ("opponent") . value = "";
        $ ("opponent") . view_text = "Friend's Number";

        view . view_field ($ ("opponent"));

        if (get_url_value ("game") != null)
        
            {
            var numbers = get_url_value ("game") . split (":");
            
            game . replay_game (numbers [0], numbers [1]);
            }

        $ ("email_address") . href = "mailto:" + get_email_address ();
        $ ("email_address") . appendChild (window . document . createTextNode (get_email_address ()));

        return;
        };
        
    var attach_event_listeners = function ()
    
        {
        var CAPTURE_PHASE = YES;
        var BUBBLE_PHASE = NO;

        window . document . addEventListener ("keydown", interrupt_cb, CAPTURE_PHASE);

        $ ("canvas") . addEventListener ("touchmove", game . t_move_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("touchstart", game . t_select_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("touchcancel", game . t_deselect_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("touchend", game . t_deselect_piece_cb, CAPTURE_PHASE);

        $ ("canvas") . addEventListener ("mousemove", game . move_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("mousedown", game . select_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("mouseout", game . deselect_piece_cb, CAPTURE_PHASE);
        $ ("canvas") . addEventListener ("mouseup", game . deselect_piece_cb, CAPTURE_PHASE);

        return;
        };

    var interrupt_cb = function (event)
    
        {
        var key = null;
        var action = null;

        switch (event . keyCode)
        
            {
            case 13: key = "enter"; break;
            case 27: key = "escape"; break;
            case 32: key = "spacebar"; break;
            case 67: key = "c"; break;
            case 68: key = "d"; break;
            case 69: key = "e"; break;
            case 72: key = "h"; break;
            case 77: key = "m"; break;
            case 80: key = "p"; break;
            case 82: key = "r"; break;
            case 83: key = "s"; break;
            case 84: key = "t"; break;
            case 85: key = "u"; break;
            
            default: key = null; break;
            }

        if (event . shiftKey) key = "shift+" + key;
        if (event . ctrlKey) key = "ctrl+" + key;
        if (event . altKey) key = "alt+" + key;
        if (event . metaKey) key = "meta+" + key;

        if (key == "enter")   action = "ajax . connect ('" + $ ("opponent") . value . replace ("'", "\\'") + "');";
        if (key == "escape")  action = "ajax . disconnect ();";
        if (key == "shift+m") action = "game . step = YES;";
        if (key == "shift+s") action = "game . step_through = YES; game . step = NO;";
        if (key == "shift+r") action = "game . step_through = NO; game . step = NO;";

        if (action != null)
        
            {
            event . preventDefault ();
            window . setTimeout (action, 0);
            }

        return;
        };

    var remove_subnodes = function (node)
    
        {
        while (node . hasChildNodes ()) node . removeChild (node . firstChild);
        
        return;
        };

    var remove_element = function (collection, element, all)

        {
        var c = null;
        
        if (collection != null)
        
            {
            c = new Array ();
            
            for (var i = 0; i < collection . length; i ++)
            
                {
                var e = collection [i];

                if (e != element) c . push (e);
                }
            }

        collection = c;
        };
