/**
 * AMF base JavaScript.
 *
 * @package    AmFlood
 * @subpackage UI
 * @copyright  Copyright 2008 Spenlen Media (http://spenlen.com)
 * @license    This source code file is licensed for the exclusive internal use of
 *             America's Flood Services, Inc. and may not be used for any other purpose.
 * @version    $Id$
 */


// Adapted from DOM Ready extension by Dan Webb
// http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
// which was based on work by Matthias Miller, Dean Edwards and John Resig
//
// Usage:
//
// Event.onReady(callbackFunction);
Object.extend(Event, {
  _domReady : function() {
    if (arguments.callee.done) { return; }
    arguments.callee.done = true;

    if (this._timer) { clearInterval(this._timer); }

    this._readyCallbacks.each(function(f) { f() });
    this._readyCallbacks = null;
  },
  onDOMReady : function(f) {
    if (!this._readyCallbacks) {
      var domReady = this._domReady.bind(this);

      if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", domReady, false);
      }
      /*@cc_on @*/
      /*@if (@_win32)
          var dummy = location.protocol == "https:" ?  "https://javascript:void(0)" : "javascript:void(0)";
          document.write("<script id=__ie_onload defer src='" + dummy + "'><\/script>");
          document.getElementById("__ie_onload").onreadystatechange = function() {
              if (this.readyState == "complete") { domReady(); }
          };
      /*@end @*/

      if (/WebKit/i.test(navigator.userAgent)) {
        this._timer = setInterval(function() {
          if (/loaded|complete/.test(document.readyState)) { domReady(); }
        }, 10);
      }

      Event.observe(window, 'load', domReady);
      Event._readyCallbacks =  [];
    }
    Event._readyCallbacks.push(f);
  }
});


/**
 * AMF global namespace object.
 * @var Object
 */
var AMF = {};


AMF.Cookie = {

    /**
     * Returns the value of the specified cookie.
     *
     * @return String
     */
    get : function (cookieName)
    {
        var cookieValue = document.cookie.match(new RegExp('(^|;)\\s*' + escape(cookieName) + '=([^;\\s]*)'));
        return (cookieValue ? unescape(cookieValue[2]) : '');
    },

    /**
     * Sets the specified browser cookie to the specified value.
     *
     * @param String cookieName
     * @param String cookieValue
     * @param Date   expirationDate (optional) If omitted, defaults to one year
     *   from today.
     */
    set : function (cookieName, cookieValue, expirationDate)
    {
        if (! expirationDate) {
            var expirationDate = new Date();
            expirationDate.setFullYear(expirationDate.getFullYear() + 1);
        }

        /** @todo Write a more appropriate path calculation. */
        newCookie = escape(cookieName) + '=' + escape(cookieValue)
                  + '; expires=' + expirationDate.toUTCString()
                  + '; path=/';

        document.cookie = newCookie;
    },

    /**
     * Sets the specified browser cookie to the specified value. Does not set
     * an expiration date, so the cookie will die with the browser session.
     *
     * @param String cookieName
     * @param String cookieValue
     */
    setSession : function (cookieName, cookieValue)
    {
        /** @todo Write a more appropriate path calculation. */
        newCookie = escape(cookieName) + '=' + escape(cookieValue)
                  + '; path=/';

        document.cookie = newCookie;
    }

};


AMF.Chat = {

    lastSequenceNumber: 0,

    autoUpdate: false,

    updateDelay: [20, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13, 13, 15, 18],
    updateDelayIndex: 0,
    updateTimer: null,

    /**
     * Initializes the chat form and registers the event handlers.
     */
    initChat : function ()
    {
        AMF.Chat.startUpdates();

        var element = $('chatMessageText');
        if (element) {
            Event.observe(element, 'keypress', AMF.Chat.watchForReturnKey);
        }
        element = $('chatMessageSend');
        if (element) {
            Event.observe(element, 'click',  AMF.Chat.postMessage);
        }
        element = $('chatMessageForm');
        if (element) {
            Event.observe(element, 'submit', AMF.Chat.postMessage);
        }

        if ((window.navigator.appName == 'Opera') && (window.history.navigationMode)) {
            window.history.navigationMode = 'compatible';
        }
        Event.observe(window, 'beforeunload', AMF.Chat.confirmLeave);
    },

    /**
     * Event handler for the chat entry field. Automatically posts the message
     * if the return or enter key is pressed.
     *
     * @param Event theEvent
     */
    watchForReturnKey : function (theEvent)
    {
        if (theEvent.keyCode == Event.KEY_RETURN) {
            Event.stop(theEvent);
            AMF.Chat.postMessage();
        }
    },

    /**
     * Event handler for the window's onunload event. Presents a confirm dialog
     * to verify the exit of the chat.
     *
     * @param Event theEvent
     */
    confirmLeave : function (theEvent)
    {
        return theEvent.returnValue = 'Are you sure you want to leave this chat?';
    },

    /**
     * Leaves the chat via an Ajax call.
     */
    leave : function ()
    {
        new Ajax.Request('/chat/live/leave', {asynchronous: false});
    },

    /**
     * Opens the chat link in a new popup window.
     *
     * @param Anchor link
     */
    launch : function (link)
    {
        window.open(link.href, link.href.replace(/.*\/(.+)$/, '$1'), 'width=400,height=500');
        if ($('chatListRows')) {
            window.setTimeout(function () {
                new Ajax.Updater('chatListRows', '/chat/agent/chatlist');
            }, 2000);
        }
        return false;
    },

    /**
     * Posts the chat message via an Ajax call.
     */
    postMessage : function ()
    {
        var messageText = $('chatMessageText');
        if (messageText.value.length < 1) {
            messageText.focus();
            return;
        }

        AMF.Chat.clearUpdateTimer();

        new Ajax.Request('/chat/chat/post', {
            parameters: {chatID:          $('chatID').value,
                         chatMessageText: messageText.value},
            on200:      AMF.Chat.updateTranscript,
            onSuccess:  AMF.Chat.ajaxHandlerUnexpextedResponse,
            onFailure:  AMF.Chat.ajaxHandlerUnexpextedResponse
        });

        messageText.value = '';
        messageText.focus();
    },

    /**
     * Starts the auto-update timer for the chat transcript.
     */
    startUpdates : function ()
    {
        AMF.Chat.autoUpdate = true;
        AMF.Chat.updateTranscript();
    },

    /**
     * Stops the auto-update timer for the chat transcript.
     */
    stopUpdates : function ()
    {
        AMF.Chat.clearUpdateTimer();
        AMF.Chat.autoUpdate = false;
    },

    /**
     * Clears the current update timer. Used to help prevent against
     * double-firing.
     */
    clearUpdateTimer : function ()
    {
        if (AMF.Chat.updateTimer) {
            window.clearTimeout(AMF.Chat.updateTimer);
            AMF.Chat.updateTimer = null;
        }
    },

    /**
     * Updates the chat transcript via an Ajax call.
     */
    updateTranscript : function ()
    {
        AMF.Chat.clearUpdateTimer();
        new Ajax.Request('/chat/chat/transcript', {
            parameters: {chatID:              $('chatID').value,
                         startSequenceNumber: (AMF.Chat.lastSequenceNumber + 1)},
            on200:      AMF.Chat.ajaxHandlerUpdateTranscript,
            onSuccess:  AMF.Chat.ajaxHandlerUnexpextedResponse,
            onFailure:  AMF.Chat.ajaxHandlerUnexpextedResponse
        });
    },

    /**
     * Ajax callback used to insert the new messages into the chat transcript.
     *
     * @param XMLHttpRequest transport
     * @param Object         json
     */
    ajaxHandlerUpdateTranscript : function (transport, json)
    {
        AMF.Chat.clearUpdateTimer();
        if (transport.responseText.length > 0) {
            var transcript = $('chatTranscript');
            new Insertion.Bottom(transcript, transport.responseText);
            AMF.Chat.lastSequenceNumber = 0;
            transcript.childElements().each(function (div) {
                if (div.id && div.id.substring(0, 12) == 'chatMessage-') {
                    AMF.Chat.lastSequenceNumber = Math.max(AMF.Chat.lastSequenceNumber, div.id.slice(12));
                }
            });
            var frame = $('chatTranscriptFrame');
            frame.scrollTop = frame.scrollHeight;
            AMF.Chat.updateDelayIndex = 0;
            try {
                niftyplayer('newMessageSound').play();
            } catch (e) {}
        }

        if (AMF.Chat.autoUpdate) {
            var delay;
            if (++AMF.Chat.updateDelayIndex >= AMF.Chat.updateDelay.length) {
                delay = AMF.Chat.updateDelay[0];
            } else {
                delay = AMF.Chat.updateDelay[AMF.Chat.updateDelayIndex];
            }
            AMF.Chat.updateTimer = window.setTimeout(AMF.Chat.updateTranscript, delay * 1000);
        }
    },

    /**
     * Ajax callback used for unexpected responses to Ajax requests.
     *
     * @param XMLHttpRequest transport
     * @param Object         json
     */
    ajaxHandlerUnexpextedResponse : function (transport, json)
    {
        new Insertion.Bottom('chatTranscript',
            '<div class="chatMessage systemMessage"><p class="messageText">'
            + 'An unexpected message was sent by the chat server ('
            + transport.status + ' ' + transport.statusText + '). Please close this '
            + 'window and begin a new chat to continue.</p></div>');
    }

};
