// Copyright (c) Day Barr 2006.  All rights reserved

var MAX_MSGS = 100;
var POLL_TIMER = 2000;

// Some prototype extensions
Object.extend(Element, {
    invisible: function() {
        for (var i = 0; i < arguments.length; i++) {
            var element = $(arguments[i]);
            element.style.visibility = 'hidden';
        }
    },

    visible: function() {
        for (var i = 0; i < arguments.length; i++) {
            var element = $(arguments[i]);
            element.style.visibility = 'visible';
        }
    },

    scrollToBottom: function(element) {
        element = $(element);
        element.scrollTop = element.scrollHeight;    
    }
});

var Chat = Class.create();
Chat.prototype =
{
    initialize: function()
    {
        this.lastEntry = 0;
        this.sessionId = null;
        this.user = null;
        this.getUpdate();
    },

    onKeyUpListener: function(ev)
    {
        $('submit').disabled = (this.textField.value.length == 0) || (this.userField.value.length == 0);
    },

    onUserChangeListener: function(ev)
    {
        if (this.userField.value.length>0)
        {
            this.user = this.userField.value;
        }
    },

    onSubmitListener: function(ev)
    {
        Event.stop(ev);
        
        if ((this.textField.value.length > 0) && (this.userField.value.length > 0)) // prevent sending nothing
        {
            var msg = Form.serialize(this.form) + '&i='+escape(this.lastEntry) + '&s='+escape(this.sessionId);

            this.submittingState(true);
            var req = new Ajax.Request(
                'chat.php',
                {method: 'post',
                parameters: msg,
                onComplete: this.onSubmitComplete.bind(this),
                onSuccess: this.onSubmitSuccess.bind(this),
                onFailure: this.onSubmitFailure.bind(this)});
        }
    },

    submittingState: function(submitting)
    {
        if (submitting)
        {
            Form.disable(this.form);
            Element.visible('sending_notification');
        }
        else
        {
            Form.enable(this.form);
            Element.invisible('sending_notification');
        }
            
    },

    onSubmitComplete: function(req)
    {
        this.submittingState(false);
        Field.activate(this.textField);
    },

    onSubmitSuccess: function(req)
    {
        Field.clear(this.textField);
        this.update(req.responseText);
    },

    onSubmitFailure: function(req)
    {
        alert("Sorry, but there was a problem submitting your message.  Perhaps the chat server is not working at the moment.  Please check back again later\n\nTechnical stuff:\nStatus = "+req.status+"\nError = "+req.responseText);
    },

    getUpdate: function()
    {
        clearTimeout(this.timer);
        var params = 'i='+this.lastEntry;
        if (this.sessionId && this.user)
        {
            params += '&u='+escape(this.user) + '&s='+escape(this.sessionId);
        }
        var req = new Ajax.Request(
            'chat.php',
            {method: 'post',
            parameters: params,
            onSuccess: this.onRecvSuccess.bind(this),
            onFailure: this.onRecvFailure.bind(this)});
    },

    update: function(content)
        {
        if (content.length==0)
        {
            // Nothing to do
            return;
        }

        content = eval("("+content+")");

        if (!this.checkFirstUpdate(content) && content.u)
        {
            // User name has been set but this is not the first message.

            // Notifiy user.
            var entry = document.createElement('div');
            Element.addClassName(entry, 'adminentry');
            entry.innerHTML = '<div class="error">The name "'+this.user+'" is already in use.  Sorry '+content.u+'</div>';
            this.history.appendChild(entry);
            setTimeout(function(){Element.scrollToBottom(this.history)}.bind(this), 1);

            // Set username back.
            Field.activate(this.userField);
            this.user = content.u;
            this.userField.value = content.u;
        }

        var _this = this;
        var added = false;
        content.c.each
        (
            function(item, index)
            {
            if (item.i > _this.lastEntry)
            {
                // Add the new message 
                var entry = document.createElement('div');
                if (item.u.length > 0)
                {
                    Element.addClassName(entry, 'chatentry');
                    entry.innerHTML = '<div class="name">'+item.u+'</div>'+
                                      '<div class="time">'+(new Date(item.t*1000).toLocaleString())+'</div>'+
                                      '<div class="message">'+item.m+'</div>';
                }
                else
                {
                    Element.addClassName(entry, 'adminentry');
                    entry.innerHTML = '<div class="message">'+item.m+'</div>';
                }
                _this.history.appendChild(entry);
                _this.lastEntry = item.i;
                added = true;
            }
        });
        // Scroll to the last new entry
        if (added)
        {
            setTimeout(function(){Element.scrollToBottom(this.history)}.bind(this), 1);
        }

        // Delete old entries to prevent indefinite growth
        var rows = this.history.childNodes.length;
        if (rows>MAX_MSGS)
        {
            for (var i=rows-MAX_MSGS; i>0; --i)
            {
                this.history.removeChild(this.history.childNodes[i-1]);
            }
            var notice = $('archivenotice');
            if (!notice)
            {
                notice = document.createElement('p');
                notice.setAttribute('id', 'archivenotice');
                notice.appendChild(document.createTextNode('Previous messages have been removed'));
                this.history.insertBefore(notice, this.history.firstChild);
            }
        }
    },

    checkFirstUpdate: function(content)
    {
        var first = false;
        if (!this.sessionId && content.s && content.u)
        {
            first = true;
            var placeholder = $('db_chat');
            if (placeholder)
            {
                placeholder.innerHTML = '<div id="history"></div><div id="entry"><form id="entryform" action="NULL" method="post"><p><label for="u" accesskey="N">Name:</label><input name="u" id="u" type="text" size="8" maxlength="10" value="'+content.u+'" /><label for="m" accesskey="S">Say:</label><input name="m" id="m" type="text" size="55" maxlength="255" value="Choose a name, then type your message here" /><input type="submit" value="send" id="submit" /><img id="sending_notification" src="imgs/loading.gif" alt="..." width="18" height="18" /></p></form></div>';
                this.history = $('history');
                this.form = $('entryform');
                this.textField = $('m');
                this.userField = $('u');
                this.sessionId = content.s;
                this.user = content.u;
            
                Field.activate(this.userField);
                this.onKeyUpListener();
    
                // Turn off IE autocomplete.
                this.textField.setAttribute('autocomplete','off');
                this.userField.setAttribute('autocomplete','off');
                
                this.textField.onkeyup = this.onKeyUpListener.bindAsEventListener(this);
                this.userField.onkeyup = this.onKeyUpListener.bindAsEventListener(this);
                this.userField.onchange = this.onUserChangeListener.bindAsEventListener(this);
    
                // Handle submit
                this.form.onsubmit = this.onSubmitListener.bindAsEventListener(this);
            }
        }
        return first;
    },
    
    onRecvSuccess: function(req)
    {
        this.update(req.responseText);
        this.timer = setTimeout(this.getUpdate.bind(this),POLL_TIMER);
    },

    onRecvFailure: function(req)
    {
        alert("Sorry, but there was a problem communicating with the chat server.\n\nError = "+req.responseText+"\n\n(Status = "+req.status+")\n\n\nPlease try again later");
    }
};

Event.observe(window, 'load', init);

function init()
{
    var talk = new Chat();
}
// Write a line of debug to the debug console, creating the debug console if it
// does not already exist in the DOM
function debug(txt)
{
    var console = $('debugconsole');
    if (!console)
    {
        // Create the console.
        // MUST have a tbody in the table for IE to display it.  Works ok
        // in FF 1.06 and Opera 8.02 with or without it.
        var console = document.createElement('div');
        var table   = document.createElement('table');
        tbody       = document.createElement('tbody');

        console.setAttribute('id', 'debugconsole');
        tbody.setAttribute('id', 'debugtbody');

        table.appendChild(tbody);
        console.appendChild(table);
        document.body.appendChild(console);
    }
    var tbody = $('debugtbody');
    if (tbody)
    {
        row = document.createElement('tr');
        addCell(row, timeStr());
        addCell(row, txt);
    
        tbody.appendChild(row);
        Element.scrollToBottom(console);
    }
}

// Returns the current time as a string
function timeStr()
{
    var today = new Date();
    var hours = today.getHours();
    var minutes = today.getMinutes();
    minutes=((minutes < 10) ? "0" : "") + minutes;
    var seconds = today.getSeconds();
    seconds=((seconds < 10) ? "0" : "") + seconds;
    var ms = today.getMilliseconds();
    ms=((ms < 100) ? "0" : "") + ((ms < 10) ? "0":"") + ms;
    return hours + ":" + minutes + ":" + seconds + "." + ms;
}

// Add a table cell to the given row element containing the given text
function addCell(row, txt)
{
    var col = document.createElement('td');
    col.innerHTML = txt;
    row.appendChild(col);
}
