
    var mm_ajax = function ()
    
        {
        this . time_stamp = null;

        this . initialize = function ()
        
            {
            this . update_time_stamp ();

            return;
            };

        this . update_time_stamp = function ()
        
            {
            this . time_stamp = new Date ();

            return;
            };

        this . is_intercepted = function (action)
        
            {
            var intercepted = NO;
            var time_stamp = new Date ();
            
            if ((time_stamp . getTime () - this . time_stamp . getTime ()) > TIMEOUT_THRESHOLD)
            
                {
                if (TRACE_AJAX) console . log ("ajax: (interception)");

                intercepted = YES;
                game . suspend (action);
                }
            
            return (intercepted);
            };

        this . get_response = function (request)

            {
            var response = null;

            if (request != null)
            if (request . responseText != null)
            if (request . responseText . substring (0, 5) == "ajax:")
                
                {
                response = request . responseText . substring (5);
                }

            return (response);
            };

        this . get_board = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_board");

            this . update_time_stamp ();
            this . get_board_b ();
            
            return;
            };

        this . get_board_b = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_board_b");
            
            this . board_request = new XMLHttpRequest ();
            this . board_request . overrideMimeType ("text/xml");
            this . board_request . onreadystatechange = this . get_board_cb;
            this . board_request . open ("GET", "./api/get-board.php");
            this . board_request . send ();

            return;
            };

        this . get_board_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_board_cb");

            var redo = ajax . board_request . readyState == 4;

            if (ajax . board_request . readyState == 4)
            if (ajax . board_request . status == 200)
            if (ajax . get_response (ajax . board_request) != null)
            if (ajax . get_response (ajax . board_request) != "")
            
                {
                redo = NO;

                game . board = ajax . get_response (ajax . board_request);
                game . board_request = null;
                }
            
            if (redo)
            
                {
                var action = "ajax . get_board_b ();";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . get_player = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_player");

            this . update_time_stamp ();
            this . get_player_b ();
            
            return;
            };

        this . get_player_b = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_player_b");

            this . player_request = new XMLHttpRequest ();            
            this . player_request . overrideMimeType ("text/xml");
            this . player_request . onreadystatechange = this . get_player_cb;
            this . player_request . open ("GET", "./api/get-player.php?board=" + game . board);
            this . player_request . send ();

            return;
            };

        this . get_player_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_player_cb");

            var redo = ajax . player_request . readyState == 4;

            if (ajax . player_request . readyState == 4)
            if (ajax . player_request . status == 200)
            if (ajax . get_response (ajax . player_request) != null)
            if (ajax . get_response (ajax . player_request) != "")
            
                {
                redo = NO;

                game . self . number = ajax . get_response (ajax . player_request);
                remove_subnodes ($ ("self"));
                $ ("self") . appendChild (window . document . createTextNode ("Your number is " + game . self . number + ""));
                }

            if (redo)
            
                {
                var action = "ajax . get_player_b ();";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }
            
            return;
            };

        this . connect = function (opponent)
        
            {
            if ((opponent == "") || (opponent == "Friend's Number"))
            
                {
                game . start_ai ();
                }
            
            else
            
                {
                if (TRACE_AJAX) console . log ("ajax: connect");

                this . update_time_stamp ();
                this . connect_b (opponent);
                }
            
            return;
            };

        this . connect_b = function (opponent)

            {
            if (TRACE_AJAX) console . log ("ajax: connect_b");

            opponent = ("" + opponent) . replace (/[^0-9]/g, "") - 0;

            if (opponent != "")
            if (opponent > 0)
            if ((opponent != game . self . number) || (game . opponent . artificial))

                {
                game . opponent . number = opponent;
                game . connecting = YES;
                game . dealer = (game . self . number < game . opponent . number) ? game . self : game . opponent;

                $ ("opponent") . value = "Connecting";
                $ ("opponent") . style . color = "#555555";
                $ ("go_button") . style . display = "none";
                $ ("stop_button") . style . display = "inline";

                this . connect_request = new XMLHttpRequest ();
                this . connect_request . overrideMimeType ("text/xml");
                this . connect_request . opponent = opponent;
                this . connect_request . onreadystatechange = this . connect_cb;
                this . connect_request . open ("GET", "./api/connect.php?board=" + game . board + "&self=" + game . self . number + "&opponent=" + game . opponent . number);
                this . connect_request . send ();
                }

            return;
            };

        this . connect_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: connect_cb");

            var redo = ajax . connect_request . readyState == 4;

            if (ajax . connect_request . readyState == 4)
            if (ajax . connect_request . status == 200)
            
                {
                redo = NO;

                $ ("opponent") . disabled = "disabled";

                game . tape = new Array ();
                game . pieces = new Array ();
                
                if (game . opponent . artificial)
                
                    {
                    game . connected = YES;

                    view . show_exchange_prompt = NO;
                    view . show_color_prompt = YES;
                    }
                
                else
                
                    {
                    ajax . get_connected ();
                    }
                }

            if (redo)
            
                {
                var r = ajax . connect_request;
                var action = "ajax . connect_b (" + r . opponent + ");";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . disconnect = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: disconnect");

            if (game . connecting == YES)
            if (game . connected == NO)

                {
                this . update_time_stamp ();
                this . disconnect_b ();
                }
            
            return;
            };

        this . disconnect_b = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: disconnect_b");

            this . disconnect_request = new XMLHttpRequest ();
            this . disconnect_request . overrideMimeType ("text/xml");
            this . disconnect_request . onreadystatechange = this . disconnect_cb;
            this . disconnect_request . open ("GET", "./api/disconnect.php?board=" + game . board + "&self=" + game . self . number);
            this . disconnect_request . send ();
            
            return;
            };

        this . disconnect_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: disconnect_cb");

            var redo = ajax . disconnect_request . readyState == 4;

            if (ajax . disconnect_request . readyState == 4)
            if (ajax . disconnect_request . status == 200)
            
                {
                redo = NO;

                $ ("opponent") . value = "";
                $ ("opponent") . blur ();

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

                $ ("go_button") . style . display = "inline";
                $ ("stop_button") . style . display = "none";

                game . opponent . number = null;
                game . opponent . artificial = NO;
                game . connecting = NO;

                $ ("opponent") . disabled = null;
                }

            if (redo)
            
                {
                var action = "ajax . disconnect_b ();";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . get_connected = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_connected");

            this . update_time_stamp ();
            this . get_connected_b ();
            
            return;
            };

        this . get_connected_b = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_connected_b");

            this . connected_request = new XMLHttpRequest ();
            this . connected_request . overrideMimeType ("text/xml");
            this . connected_request . onreadystatechange = this . get_connected_cb;
            this . connected_request . open ("GET", "./api/get-connected.php?self=" + game . self . number + "&opponent=" + game . opponent . number);
            this . connected_request . send ();
            
            return;
            };

        this . get_connected_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_connected_cb");

            var redo = ajax . connected_request . readyState == 4;

            if (ajax . connected_request . readyState == 4)
            if (ajax . connected_request . status == 200)
            if (ajax . get_response (ajax . connected_request) != null)
            if (ajax . get_response (ajax . connected_request) == "YES")

                {
                redo = NO;

                game . connected = YES;
                view . show_exchange_prompt = NO;

                if (game . dealer == game . opponent) ajax . get_color ();
                else view . show_color_prompt = YES;
                }
            
            if (redo && game . connecting)
            
                {
                var action = "ajax . get_connected_b ();";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . get_color = function ()
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_color");

            this . update_time_stamp ();
            this . get_color_b ();
            
            return;
            };

        this . get_color_b = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_color_b");

            view . show_color_prompt = NO;

            this . color_request = new XMLHttpRequest ();
            this . color_request . overrideMimeType ("text/xml");
            this . color_request . onreadystatechange = this . get_color_cb;
            this . color_request . open ("GET", "./api/get-color.php?self=" + game . self . number + "&board=" + game . board);
            this . color_request . send ();

            return;
            };

        this . get_color_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_color_cb");

            var redo = ajax . color_request . readyState == 4;

            if (ajax . color_request . readyState == 4)
            if (ajax . color_request . status == 200)
            if (ajax . get_response (ajax . color_request) != null)
            if (ajax . get_response (ajax . color_request) != "")

                {
                redo = NO;

                game . self . color = ajax . get_response (ajax . color_request);
                game . opponent . color = (game . self . color == "white") ? "black" : "white";
                game . turn = (game . self . color == "white") ? game . self : game . opponent;

                game . reset ();

                if (game . turn == game . opponent) ajax . get_move (game . get_move_count ());
                }

            if (redo)
            
                {
                var action = "ajax . get_color_b ();";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . set_color = function (color)

            {
            if (TRACE_AJAX) console . log ("ajax: set_color");

            this . update_time_stamp ();
            this . set_color_b (color);
            
            return;
            };

        this . set_color_b = function (color)

            {
            if (TRACE_AJAX) console . log ("ajax: set_color_b");

            game . self . color = color;
            game . opponent . color = (game . self . color == "white") ? "black" : "white";
            game . turn = (game . self . color == "white") ? game . self : game . opponent;

            this . color_request = new XMLHttpRequest ();
            this . color_request . overrideMimeType ("text/xml");
            this . color_request . onreadystatechange = this . set_color_cb;
            this . color_request . open ("GET", "./api/set-color.php?self=" + game . self . number + "&color=" + game . self . color + "&board=" + game . board);
            this . color_request . send ();

            return;
            };

        this . set_color_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: set_color_cb");

            var redo = ajax . color_request . readyState == 4;

            if (ajax . color_request . readyState == 4)
            if (ajax . color_request . status == 200)

                {
                redo = NO;

                view . show_color_prompt = NO;

                game . turn = (game . self . color == "white") ? game . self : game . opponent;
                game . reset_pieces (ANIMATE);
                game . moves = new Array ();

                if (game . turn == game . opponent)
                
                    {
                    if (game . opponent . artificial)
                    
                        {
                        window . setTimeout ("ai . choose_move ('" + game . opponent . color + "');", 2000);
                        }
                    
                    else // human oppponent
                    
                        {
                        ajax . get_move (game . get_move_count ());
                        }
                    }
                }

            if (redo)
            
                {
                var action = "ajax . set_color_b ('" + game . self . color + "');";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . get_move = function (number)
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_move");

            this . update_time_stamp ();
            this . get_move_b (number);
            
            return;
            };
        
        this . get_move_b = function (number)
            
            {
            if (TRACE_AJAX) console . log ("ajax: get_move_b");


         // Retain the data in the request (in case it needs to be resent) and then send the data.

            this . get_move_request = new XMLHttpRequest ();
            this . get_move_request . move_number = number;
            this . get_move_request . overrideMimeType ("text/xml");
            this . get_move_request . onreadystatechange = this . get_move_cb;
            this . get_move_request . open ("GET", "./api/get-move.php?self=" + game . self . number + "&opponent=" + game . opponent . number + "&board=" + game . board + "&number=" + number);
            this . get_move_request . send ();

            return;
            };

        this . get_move_cb = function ()
            
            {
            if (TRACE_AJAX) console . log ("ajax: get_move_cb");

            var redo = ajax . get_move_request . readyState == 4;

            if (ajax . get_move_request . readyState == 4)
            if (ajax . get_move_request . status == 200)
            if (ajax . get_response (ajax . get_move_request) != null)
            if (ajax . get_response (ajax . get_move_request) != "")

                {
                redo = NO;

                var data = ajax . get_response (ajax . get_move_request) . split (",");
                var move = new mm_move (data [1], data [2], data [3], data [4], (data [5] == "") ? null : data [5]);

                if ((game . self . color == "black") || ((game . opponent . color == "white") && game . opponent . artificial))

                    {
                 // Translate the coordinates.

                    move . fx = 7 - move . fx;
                    move . fy = 7 - move . fy;
                    move . tx = 7 - move . tx;
                    move . ty = 7 - move . ty;
                    }

                if (data [0] == game . get_move_count ())
                
                    {
                    game . do_move (move);
                    game . alternate_turn ();
                    }
                }

            if (redo)
            
                {
                var action = "ajax . get_move_b (" + ajax . get_move_request . move_number + ");";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . set_move = function (number, move)
        
            {
            if (TRACE_AJAX) console . log ("ajax: set_move");
            
            var translated_move = new mm_move (move . fx, move . fy, move . tx, move . ty, move . promotion);
            
            if ((game . self . color == "black") || ((game . opponent . color == "white") && game . opponent . artificial))

                {
             // Translate the coordinates.

                translated_move . fx = 7 - translated_move . fx;
                translated_move . fy = 7 - translated_move . fy;
                translated_move . tx = 7 - translated_move . tx;
                translated_move . ty = 7 - translated_move . ty;
                }

            this . update_time_stamp ();
            this . set_move_b (number, translated_move . fx, translated_move . fy, translated_move . tx, translated_move . ty, translated_move . promotion);
            
            return;
            };

        this . set_move_b = function (number, fx, fy, tx, ty, promotion)
        
            {
            if (TRACE_AJAX) console . log ("ajax: set_move_b");


         // Retain the data in the request (in case it needs to be resent) and then send the data.

            this . set_move_request = new XMLHttpRequest ();
            this . set_move_request . move_number = number;
            this . set_move_request . move_fx = fx;
            this . set_move_request . move_fy = fy;
            this . set_move_request . move_tx = tx;
            this . set_move_request . move_ty = ty;
            this . set_move_request . move_promotion = promotion;
            this . set_move_request . overrideMimeType ("text/xml");
            this . set_move_request . onreadystatechange = this . set_move_cb;
            this . set_move_request . open ("GET", "./api/set-move.php?self=" + game . self . number + "&opponent=" + game . opponent . number + "&board=" + game . board + "&number=" + number + "&fx=" + fx + "&fy=" + fy + "&tx=" + tx + "&ty=" + ty + "&promotion=" + ((promotion == null) ? "" : promotion));
            this . set_move_request . send ();

            return;
            };
        
        this . set_move_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: set_move_cb");

            var redo = ajax . set_move_request . readyState == 4;

            if (ajax . set_move_request . readyState == 4)
            if (ajax . set_move_request . status == 200)
            if (ajax . get_response (ajax . set_move_request) != null)
            if (ajax . get_response (ajax . set_move_request) == "RECEIVED")

                {
                redo = NO;

                game . alternate_turn ();
                
                if (game . turn == game . opponent)
                
                    {
                    if (game . opponent . artificial)
                    
                        {
                        window . setTimeout ("ai . choose_move ('" + game . opponent . color + "');", 250);
//                        ai . choose_move (game . opponent . color);
                        }
                    
                    else
                    
                        {
                        ajax . get_move (game . get_move_count ());
                        }
                    }
                }

            if (redo)
            
                {
                var r = ajax . set_move_request;
                var action = "ajax . set_move_b (" + r . move_number + ", " + r . move_fx + ", " + r . move_fy + ", " + r . move_tx + ", " + r . move_ty + ", '" + ((r . move_promotion == null) ? "" : r . move_promotion) + "');";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . set_winner = function (winner)
        
            {
            if (TRACE_AJAX) console . log ("ajax: set_winner");
            
            game . turn = null;
            game . winner = winner;

            this . update_time_stamp ();
            this . set_winner_b (winner);
            
            return;
            };

        this . set_winner_b = function (winner)
        
            {
            if (TRACE_AJAX) console . log ("ajax: set_winner_b");


         // Retain the data in the request (in case it needs to be resent) and then send the data.

            this . set_winner_request = new XMLHttpRequest ();
            this . set_winner_request . winner = winner;
            this . set_winner_request . overrideMimeType ("text/xml");
            this . set_winner_request . onreadystatechange = this . set_winner_cb;
            this . set_winner_request . open ("GET", "./api/set-winner.php?self=" + game . self . number + "&opponent=" + game . opponent . number + "&board=" + game . board + "&winner=" + winner);
            this . set_winner_request . send ();

            return;
            };
        
        this . set_winner_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: set_winner_cb");

            var redo = ajax . set_winner_request . readyState == 4;

            if (ajax . set_winner_request . readyState == 4)
            if (ajax . set_winner_request . status == 200)
            if (ajax . get_response (ajax . set_winner_request) != null)
            if (ajax . get_response (ajax . set_winner_request) == "RECEIVED")

                {
                redo = NO;
                }

            if (redo)
            
                {
                var r = ajax . set_winner_request;
                var action = "ajax . set_winner_b ('" + r . winner + "');";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };

        this . get_moves = function (player_a, player_b)
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_moves");
            
            this . update_time_stamp ();
            this . get_moves_b (player_a, player_b);
            
            return;
            };

        this . get_moves_b = function (player_a, player_b)
        
            {
            if (TRACE_AJAX) console . log ("ajax: get_moves_b");


         // Retain the data in the request (in case it needs to be resent) and then send the data.

            this . get_moves_request = new XMLHttpRequest ();
            this . get_moves_request . player_a = player_a;
            this . get_moves_request . player_b = player_b;
            this . get_moves_request . overrideMimeType ("text/xml");
            this . get_moves_request . onreadystatechange = this . get_moves_cb;
            this . get_moves_request . open ("GET", "./api/get-moves.php?player_a=" + player_a + "&player_b=" + player_b);
            this . get_moves_request . send ();

            return;
            };
        
        this . get_moves_cb = function ()

            {
            if (TRACE_AJAX) console . log ("ajax: get_moves_cb");

            var redo = ajax . get_moves_request . readyState == 4;

            if (ajax . get_moves_request . readyState == 4)
            if (ajax . get_moves_request . status == 200)
            if (ajax . get_response (ajax . get_moves_request) != null)
            if (ajax . get_response (ajax . get_moves_request) != "")

                {
                if (ajax . get_response (ajax . get_moves_request) != "{}")
                
                    {
                    game . demonstration = ajax . get_response (ajax . get_moves_request);
                    game . demonstrate (YES);
                    }

                redo = NO;
                }

            if (redo)
            
                {
                var r = ajax . get_moves_request;
                var action = "ajax . get_moves_b (" + r . player_a + ", " + r . player_b + ");";

                if (! ajax . is_intercepted (action)) window . setTimeout (action, AJAX_DELAY);
                }

            return;
            };
        };