﻿// =========================================================================
// PUBLIC METHODS:
//
//  GetConnection()
//  PushText(strContent)
//  Terminate()
//  HardTerminate()
//
// CALLBACKS (DEFINED AS PARAMETERS IN CLASS CONSTRUCTOR):
//
//  CallbackState(ConnectionId, IsValid, IsAuthorised)
//  CallbackContent(Content)
// =========================================================================
function CChat_Interface(fncCallbackState, fncCallbackContent)
{
    // ========================================================
    // INITIALISE CLASS
    // ========================================================
    // Record callback function pointers
    // NB: Test parameters..
    var _fncCallbackState = fncCallbackState;
    var _fncCallbackContent = fncCallbackContent;

    // Record connection state info
    var _ConnectionId = null;
    var _bAuthorised = false;
    
    // Keep track of content-retrieval timer
    var _intTimerId = null;
    
    // Record retrieved entries.
    var _intRetrievedItems = 0;
    
    // ========================================================
    // REQUEST CONNECTION
    // ========================================================
    this.GetConnection = GetConnection;
    function GetConnection()
    {
        Chat.RequestConnection(ConnectionRequestCallback);

        function ConnectionRequestCallback(bSuccess, strId, strMessage)
        {
            // If failed, display message and do nothing
            if (!bSuccess)
            {
                alert("Connection Denied:\n\n" + strMessage);
                _ConnectionId = null;
                return;
            }
            
            // Record designated Connection Id
            _ConnectionId = strId;
            CallbackStateWrapper(true, false);
            
            // Mark as currently un-authorised
            _bAuthorised = false;
            
            // Reset "retrieved content" info
            _intRetrievedItems = 0;


            // Start testing for connection authorisation
            TestForAuthorisation();
        }
    }

    function TestForAuthorisation()
    {
        // Cancel any content-retrieval timer
        CancelContentRetrievalTimer();

        // Initiate a connection test request
        if (_ConnectionId != null)
            Chat.TestConnectionValid(_ConnectionId, ConnectionConfirmationCallback);

        function ConnectionConfirmationCallback(bSuccess, bValid, bAuthorised)
        {
            // If connection not valid, update state
            if (!bValid)
            {
                // If connection id no longer valid, give up
                _ConnectionId = null;
                _bAuthorised = false;
                CallbackStateWrapper(false, false);
                return;
            }
            if (!bAuthorised)
            {
                // If id valid, but not yet authorised, test again soon
                _bAuthorised = false;
                CallbackStateWrapper(true, false);
                setTimeout(TestForAuthorisation, 500);
                return;
            }
            _bAuthorised = true;
            CallbackStateWrapper(true, true);
            
            // If successful, prepare a content-retrieval timer
            StartContentRetrievalTimer();
        }
    }

    // ========================================================
    // TERMINATE CURRENT CONNECTION
    // ========================================================
    this.Terminate = Terminate;
    function Terminate()
    {
        _bAuthorised = false;
        CancelContentRetrievalTimer();
        if (_ConnectionId != null)
            Chat.Terminate(_ConnectionId, TeminateCallback);

        function TeminateCallback(bSuccess)
        {
            CallbackStateWrapper(false, false);
        }
    }

    // ========================================================
    // TERMINATE CURRENT CONNECTION
    // - SYNCHRONOUS REQUEST (USED WHEN LEAVING PAGE TO ENSURE
    //   REQUEST IS PROCESSED BEFORE WE UNLOAD PAGE)
    // ========================================================
    this.HardTerminate = HardTerminate;
    function HardTerminate()
    {
        _bAuthorised = false;
        CancelContentRetrievalTimer();
        if (_ConnectionId != null)
            Chat.Terminate(_ConnectionId, null, false);
    }

    // ========================================================
    // RETRIEVE ANY NEW CONTENT FROM SERVER
    // ========================================================
    function CheckForNewContent()
    {
        // Ask server how many entries have been made for
        // this connection
        Chat.GetTextCount(_ConnectionId, ContentCountCallback);
    
        function ContentCountCallback(bSuccess, intCount)
        {
            // If fail, test whether the connection is still valid.
            // (If it is, then the timer will restart for this
            // CheckForNewContent function)
            if (!bSuccess)
            {
                TestForAuthorisation();
                return;
            }
            
            // If there are more entries on the server than
            // we've retrieved, try to pull back this data
            if (intCount > _intRetrievedItems)
            {
                // Request entry after the highest entry
                // that we've already got
                GetContent(_intRetrievedItems);
                return;
            }

            // Restart content timer
            StartContentRetrievalTimer();
        }
    }
    
    function GetContent(intIndex)
    {
        Chat.GetText(_ConnectionId, intIndex, GetContentCallback);

        function GetContentCallback(bSuccessServer, bValidIndex, intIndex, strContent)
        {
            // If failed to contact server, test connection still valid
            // (If it is, then we'll go back through the test-for-content
            // process). NB: Shouldn't really have to worry about bValidIndex
            // not being true as it's the value returned from the server, but
            // can safely lump it in here as it'll be refreshed once we confirm
            // the connection is still valid.
            if ((!bSuccessServer) || (!bValidIndex))
            {
                TestForAuthorisation();
                return;
            }
            
            // Update retrieved-items record
            CallbackContentWrapper(intIndex, strContent);
            _intRetrievedItems = intIndex + 1;

            // Restart content timer
            StartContentRetrievalTimer();
        }
    }

    // ========================================================
    // HANDLE CONTENT-RETRIEVAL TIMER
    // ========================================================
    function StartContentRetrievalTimer()
    {
        // Cancel any existing retrieval timer
        CancelContentRetrievalTimer();
        
        // Start off a new one
        _intTimerId = setTimeout(CheckForNewContent, 1000);
    }

    function CancelContentRetrievalTimer()
    {
        if (_intTimerId != null)
        {
            clearTimeout(_intTimerId);
            _intTimerId = null;
        }
    }

    // ========================================================
    // POST TEXT
    // ========================================================
    this.PushText = PushText;
    function PushText(strContent)
    {
        // If no text specified, do nothing
        if (!ObjectDetection.IsString(strContent))
            return;

        // Push request to server
        Chat.PushText(_ConnectionId, strContent, GetContentCallback);

        function GetContentCallback()
        {
            // Don't bother doing anything at this point, just let
            // the content-retrieval timer pick it up
        }
    }
    
    // ========================================================
    // WRAP CALLBACK FUNCTIONS TO UPDATE INTERNAL VALUES
    // ========================================================
    function CallbackStateWrapper(bValid, bAuthorised)
    {
        // Update internal values
        if (!bValid)
            _ConnectionId = null;
        _bAuthorised = bAuthorised;

        // Make callback
        _fncCallbackState(_ConnectionId, bValid, bAuthorised);
    }
    
    function CallbackContentWrapper(intIndex, strContent)
    {
        _fncCallbackContent(strContent);
    }
}
