﻿//////////////////////
// PORTIONS COPYRIGHT 2009 DUCK POND, INC.
//////////////////////

/// <reference path="../JavaScript/MicrosoftAjax/MicrosoftAjax.debug.js" />
/// <reference path="../JavaScript/jquery/jquery-1.3.2-vsdoc2.js" />

Type.registerNamespace("DuckPond.Zuild.WebServer.Controls");


/////////////////////
// CONSTRUCTOR
/////////////
DuckPond.Zuild.WebServer.Controls.ChatClient = function(vars)
{
    var This = this;

    //////
    // store values
    if (typeof (vars.updateIntervalCoefficient) != "number")
    {
        vars.updateIntervalCoefficient = 1.0;
    }
    else if (vars.updateIntervalCoefficient < 0.1)
    {
        vars.updateIntervalCoefficient = 0.1;
    }
    else if (vars.updateIntervalCoefficient > 100.0)
    {
        vars.updateIntervalCoefficient = 100.0;
    }
    this._TimestampInitial = vars.initialTimestamp;
    this._TimestampCurrent = this._TimestampInitial;
    this._MessagesAreBeingRetrieved = false;
    this._RoomId = vars.RoomId;
    this._FullPage = vars.FullPage;
    this._ChatMessageTemplate = vars.ChatMessageTemplate;
    this._AutoInsertJoinMessage = vars["AutoInsertJoinMessage"];
    this._InsertMessagesAtTop = vars["InsertMessagesAtTop"];

    this._DisplayModeratorOptions = vars["DisplayModeratorOptions"];

    this._EnableFacebookStatusUpdate = vars["EnableFacebookStatusUpdate"];
    this._FacebookStatusUpdateSuffix = vars["FacebookStatusUpdateSuffix"];

    this._MessageCheckIntervalInitial = 100 * vars.updateIntervalCoefficient;
    this._MessageCheckIntervalIdle = 8000 * vars.updateIntervalCoefficient;
    this._MessageCheckIntervalActive = 2000 * vars.updateIntervalCoefficient;
    this._WhosOnlineCheckIntervalInitial = 500 * vars.updateIntervalCoefficient;
    this._WhosOnlineCheckIntervalNormal = 10000 * vars.updateIntervalCoefficient;
    this._PageSize = vars.PageSize;


    //////
    // gather elements
    this._jqRoot = $("#" + vars.RootElementId);
    if (vars.Panel_IncomingChat != null)
    {
        this._Panel_IncomingChat = $("#" + vars.Panel_IncomingChat)[0];
    }
    if (vars.Button_SendMessage != null)
    {
        this._Button_SendMessage = $("#" + vars.Button_SendMessage)[0];
    }
    if (vars.Button_PopOut != null)
    {
        this._Button_PopOut = $("#" + vars.Button_PopOut)[0];
    }
    if (vars.TextBox_SendMsg != null)
    {
        this._TextBox_SendMsg = $("#" + vars.TextBox_SendMsg)[0];
    }
    if (vars.Panel_WhosOnline != null)
    {
        this._Panel_WhosOnline = $("#" + vars.Panel_WhosOnline)[0];
    }
    this._ShowParticipantList = this._Panel_WhosOnline != null;

    this._jqPagingParent = this._jqRoot.find(".jqPageParent");
    this._jqPagingFirst = this._jqRoot.find(".jqPageFirst");
    this._jqPagingPrevious = this._jqRoot.find(".jqPagePrevious");
    this._jqPagingCurrent = this._jqRoot.find(".jqPageCurrent");
    this._jqPagingNext = this._jqRoot.find(".jqPageNext");
    this._jqPagingBar = this._jqRoot.find(".jqPageBar");

    this._jqPagingParent.css("visibility", "hidden");


    //////
    // set up  event handlers
    if (this._TextBox_SendMsg != null)
    {
        $(this._TextBox_SendMsg).keypress(function(e) { This.TextBoxChangeEvent(e); });
        this._TextBox_SendMsg.value = this.EnterTextInitialMessage;

        $(this._TextBox_SendMsg).bind("focus", function() { if (This._TextBox_SendMsg.value === This.EnterTextInitialMessage) { This._TextBox_SendMsg.select(); } });

        $(this._TextBox_SendMsg).click(function(e) { This._TextBox_SendMsg.value = ''; $(This._TextBox_SendMsg).select(); });

        $(this._TextBox_SendMsg).bind("focus", null, function() { FB.Connect.requireSession(function() { }, function() { }, true); });

        // auto-focus the textbox
        // window.setTimeout(function() { $(This._TextBox_SendMsg).focus(); $(This._TextBox_SendMsg).select(); }, 1);
    }

    if (this._Button_SendMessage != null)
    {
        $(this._Button_SendMessage).click(function() { This.SendMessage(); });
    }

    if (this._Button_PopOut != null)
    {
        $(this._Button_PopOut).click(function() { This.ButtonPopOutClicked(); });
    }

    // update on each resize?
    if (this._FullPage)
    {
        $addHandler(window, 'resize', function() { This.UpdateLayout(); });

        // add a deferred layout update call right away
        window.setTimeout(function() { This.UpdateLayout(); }, 250);
    }

    this._jqPagingFirst.click(function() { This.NavigateToPage(1); });
    this._jqPagingPrevious.click(function() { This.NavigateToPage(This._PageNumber - 1); });
    this._jqPagingNext.click(function() { This.NavigateToPage(This._PageNumber + 1); });



    //////
    // grab messages in a moment
    window.setTimeout(
        function() { This.NavigateToPage(1); },
        this._MessageCheckIntervalInitial);


    //////
    // misc

    // auto insert the join message?
    if (this._AutoInsertJoinMessage)
    {
        $(this._TextBox_SendMsg).val("/me has entered chat.");
        this.SendMessage();
    }
}


/////////////////////
// PROTOTYPE
/////////////
DuckPond.Zuild.WebServer.Controls.ChatClient.prototype =
{
    /////////////////////
    // CONSTANTS
    /////////////
    EnterTextInitialMessage: " Post your comments on healthcare and government spending",


    /////////////////////
    // FIELDS
    /////////////
    _jqRoot: null,
    _Panel_IncomingChat: null,
    _TextBox_SendMsg: null,
    _Button_SendMessage: null,
    _Button_PopOut: null,
    _Panel_WhosOnline: null,

    _TimestampInitial: 0,
    _TimestampCurrent: 0,
    _FullPage: null,
    _MessagesAreBeingRetrieved: null,
    _RoomId: null,
    _ConnectivityWarningIssued: false,

    _ChatMessageTemplate: null,
    _RowStyleOscilation: 0,

    _AutoInsertJoinMessage: false,
    _InsertMessagesAtTop: false,
    _DisplayModeratorOptions: false,
    _EnableFacebookStatusUpdate: false,

    // the current setTimeout handle for the GetMessages cascade.
    _HandleTimeoutCascade_GetMessages: null,
    _PageNumber: 1,
    _PageSize: 10,
    _ResultsCountPage1Original: null,
    _NumberOfPages: 1,

    // paging links
    _jqPagingParent: null,
    _jqPagingFirst: null,
    _jqPagingBar: null,
    _jqPagingPrevious: null,
    _jqPagingCurrent: null,
    _jqPagingNext: null,


    /////////////////////
    // METHODS: ui
    /////////////
    NavigateToPage: function(pageNumber)
    {
        var This = this;

        if (pageNumber < 1)
        {
            pageNumber = 1;
        }

        var force = false;
        if (this._PageNumber === 1 || (this._PageNumber !== pageNumber))
        {
            force = true;
        }

        this._PageNumber = pageNumber;
        this._ResultsCountPage1Original = null;
        this._TimestampCurrent = this._TimestampInitial;
        this._jqPagingCurrent.text("Page " + this._PageNumber.toString() + " of " + this._NumberOfPages.toString());
        this.GetPageCount();
        this.GetMessages(force);
    },

    UpdateLayout: function()
    {
        // grab browser height
        var browserHeight = window.innerHeight;
        if (typeof (browserHeight) == "undefined" || browserHeight == null || browserHeight == 0)
        {
            browserHeight = document.body.offsetHeight;
        }

        // grab browser width
        var browserWidth = window.innerWidth;
        if (typeof (browserWidth) == "undefined" || browserWidth == null || browserWidth == 0)
        {
            browserWidth = document.body.offsetWidth;
        }

        var newHeightOfChatLog = browserHeight - 72;
        if (newHeightOfChatLog <= 16)
        {
            newHeightOfChatLog = 16;
        }
        this._Panel_IncomingChat.style.height = newHeightOfChatLog + "px";
    },

    TextBoxChangeEvent: function(e)
    {
        if (!e) e = window.event
        var mykey, ctrl, shift;

        mykey = e.charCode;
        if (mykey == null || mykey == 0)
        {
            if (e.which != null)
            {
                mykey = e.which;
            }
            else
            {
                mykey = e.keyCode;
            }
        }
        ctrl = e.ctrlKey;
        shift = e.shiftKey;

        if ((shift && mykey == 13) || (ctrl && mykey == 13))
        {
            try { e.preventDefault(); } catch (exc) { }
            try { e.stopPropagation(); } catch (exc) { }
            return false;
        }
        else if (mykey == 13 || mykey == 10)
        {
            // prevent enter key from being pressed if text box empty
            if (this._TextBox_SendMsg.value == '')
            {
                try { e.preventDefault(); } catch (exc) { }
                try { e.stopPropagation(); } catch (exc) { }
                return false;
            }

            this.SendMessage();
            try { e.preventDefault(); } catch (exc) { }
            try { e.stopPropagation(); } catch (exc) { }
            return false;
        }

        return true;
    },

    InsertNewMessage: function(chatData)
    {
        var This = this;

        var newContent = this._ChatMessageTemplate;
        var rowStyle;
        if (this._RowStyleOscilation == 0)
        {
            rowStyle = "list";
            this._RowStyleOscilation = 1;
        }
        else
        {
            rowStyle = "list alt";
            this._RowStyleOscilation = 0;
        }

        var sourceNetwork;
        if (chatData.UserUri.indexOf("facebook.com") != -1)
        {
            sourceNetwork = "";
        }
        else if (chatData.UserUri.indexOf("twitter.com") != -1)
        {
            sourceNetwork = " from Twitter";
        }
        else
        {
            sourceNetwork = "";
        }

        var userDisplayName = chatData.UserDisplayName;
        if (userDisplayName == null
            || userDisplayName === "null"
            || userDisplayName == "")
        {
            userDisplayName = "User";
        }

        var userProfilePic = chatData.UserProfilePic;
        if (userProfilePic == null
            || userProfilePic === "null.null"
            || userProfilePic == "")
        {
            userProfilePic = "http://static.ak.connect.facebook.com/pics/t_silhouette.jpg";
        }

        newContent
            = newContent
                .replace(/{{row css}}/g, rowStyle)
                .replace(/{{user picture}}/g, userProfilePic)
                .replace(/{{user name}}/g, userDisplayName)
                .replace(/{{chat message}}/g, chatData.Message)
                .replace(/{{timestamp}}/g, chatData.AdjustedTimestamp)
                .replace(/{{user uri}}/g, chatData.UserUri)
                .replace(/{{source}}/g, sourceNetwork);

        var newNode = $(newContent);
        newNode.data("ChatData", chatData);

        // if we need to hide the moderator options
        if (!this._DisplayModeratorOptions)
        {
            newNode.find(".moderatorOptions").remove();
        }
        // if we need to display the moderator options
        else
        {
            // bind event handlers to the moderator commands
            var showHideMessage = newNode.find(".moderatorOptions .jqShowHideMessage");
            var banUser = newNode.find(".moderatorOptions .jqBanUser");

            showHideMessage.click(function()
            {
                This.ModerationShowHideMessage(chatData["MessageId"], newNode);
            });

            banUser.click(function()
            {
                This.ModerationBanUserByMessageId(chatData["MessageId"]);
            });
        }

        // is this a hidden (moderated) message? apply appropriate sytle
        if (chatData["IsHidden"] === true)
        {
            newNode.find(".message").addClass("hiddenmessage");
        }

        if (this._InsertMessagesAtTop)
        {
            this._Panel_IncomingChat.insertBefore(newNode[0], this._Panel_IncomingChat.firstChild);
        }
        else
        {
            this._Panel_IncomingChat.appendChild(newNode[0]);
        }
    },

    ButtonPopOutClicked: function()
    {
        window.open(
            "/MediaSocial/Chat.aspx/" + this._RoomId.toString(),
            "MediaSocialChat",
            "width=644,height=447,toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=0,resizable=0",
            false);
    },

    ClearMessagesFromUI: function()
    {
        $(this._Panel_IncomingChat).empty();
    },
    

    /////////////////////
    // METHODS: web service
    /////////////
    GetPageCount: function()
    {
        var This = this;

        DuckPond
        .Zuild
        .WebServer
        .Services
        .Chat
        .GetPageCount(
            this._RoomId,
            this._PageSize,
            function(result)
            {
                This._NumberOfPages = result;
                This._jqPagingCurrent.text("Page " + This._PageNumber.toString() + " of " + This._NumberOfPages.toString());
            },
            function()
            {
            });
    },

    GetMessages: function(force)
    {
        var This = this;

        if (this._MessagesAreBeingRetrieved && force !== true)
        {
            return;
        }

        // clear the timeout for any existing cascade.
        if (this._HandleTimeoutCascade_GetMessages != null)
        {
            window.clearTimeout(this._HandleTimeoutCascade_GetMessages);
            this._HandleTimeoutCascade_GetMessages = null;
        }

        this._MessagesAreBeingRetrieved = true;


        if (this._PageNumber === 1)
        {
            DuckPond
            .Zuild
            .WebServer
            .Services
            .Chat
            .GetLatestMessages(
                this._RoomId,
                this._TimestampCurrent,
                this._PageSize,
                function(result) { This.GetMessagesSuccess(result); },
                function(error) { This.GetMessagesFailure(error); });
        }
        else
        {
            DuckPond
            .Zuild
            .WebServer
            .Services
            .Chat
            .GetLatestMessagesPaged(
                this._RoomId,
                this._PageNumber,
                this._PageSize,
                function(result) { This.GetMessagesSuccess(result); },
                function(error) { alert('Could not retrieve messages.'); });

        }
    },

    GetMessagesSuccess: function(result)
    {
        var _this = this;
        var isIncrementalResponse = this._ResultsCountPage1Original !== null;
        this._jqPagingParent.css("visibility", "visible");

        var shouldDivBeScrolled;
        if (this._InsertMessagesAtTop === false)
        {
            if (this._Panel_IncomingChat.scrollTop + this._Panel_IncomingChat.clientHeight < this._Panel_IncomingChat.scrollHeight)
            {
                shouldDivBeScrolled = false;
            }
            else
            {
                shouldDivBeScrolled = true;
            }
        }
        else
        {
            shouldDivBeScrolled = false;
        }

        var myTimeoutDuration = this._MessageCheckIntervalIdle;
        if (result.chatData.length == 0)
        {
            this._TimestampCurrent = result.Timestamp;
        }
        else
        {
            if (!isIncrementalResponse)
            {
                this.ClearMessagesFromUI();
            }

            var iMax = result.chatData.length;
            var iInit = iMax > this._PageSize ? 1 : 0;
            for (var i = iInit; i < iMax; ++i)
            {
                this.InsertNewMessage(result.chatData[i]);
            }
            this._TimestampCurrent = result.chatData[result.chatData.length - 1].LongTimestamp;
        }
        myTimeoutDuration = this._MessageCheckIntervalActive; // shorter timeout because it seems like people are conversing...

        if (this._PageNumber === 1 && !isIncrementalResponse)
        {
            this._ResultsCountPage1Original = result.chatData.length;
        }

        // hide the next button?
        if (isIncrementalResponse)
        {
            if (this._ResultsCountPage1Original > this._PageSize)
            {
                this._jqPagingNext.css("visibility", "visible");
            }
            else
            {

            }
        }
        else if (result.chatData.length <= this._PageSize)
        {
            this._jqPagingNext.css("visibility", "hidden");
        }
        else
        {
            this._jqPagingNext.css("visibility", "visible");
        }
        // hide the previous button?
        if (this._PageNumber === 1)
        {
            this._jqPagingFirst.css("visibility", "hidden");
            this._jqPagingBar.css("visibility", "hidden");
            this._jqPagingPrevious.css("visibility", "hidden");
        }
        else if (this._PageNumber === 2)
        {
            this._jqPagingFirst.css("visibility", "hidden");
            this._jqPagingBar.css("visibility", "hidden");
            this._jqPagingPrevious.css("visibility", "visible");
        }
        else
        {
            this._jqPagingFirst.css("visibility", "visible");
            this._jqPagingBar.css("visibility", "visible");
            this._jqPagingPrevious.css("visibility", "visible");
        }

        // scroll to bottom of div
        if (shouldDivBeScrolled)
        {
            this._Panel_IncomingChat.scrollTop = this._Panel_IncomingChat.scrollHeight;
        }

        // record that we're done
        this._MessagesAreBeingRetrieved = false;

        // keep the cascade alive
        if (this._PageNumber === 1)
        {
            this._HandleTimeoutCascade_GetMessages
                = window.setTimeout(function() { _this.GetMessages(false); }, myTimeoutDuration);
        }
    },

    GetMessagesFailure: function(error)
    {
        var This = this;
        this._MessagesAreBeingRetrieved = false;

        if (!this._ConnectivityWarningIssued)
        {
            //alert("Connection was lost while receiving the latest chat messages.");
            //this._ConnectivityWarningIssued = true;
        }

        this._HandleTimeoutCascade_GetMessages
            = window.setTimeout(function() { This.GetMessages(false); }, this._MessageCheckIntervalIdle);
    },

    SendMessage: function()
    {
        var This = this;

        // currently disallow blank messages
        if (this._TextBox_SendMsg.value == "")
        {
            return;
        }

        var message = this._TextBox_SendMsg.value;

        if (this._EnableFacebookStatusUpdate)
        {
            var messageToPostToFacebook = message + This._FacebookStatusUpdateSuffix;
            messageToPostToFacebook
                = messageToPostToFacebook
                    .replace(/\n/g, " ")
                    .replace(/\r/g, " ");

            FB.Facebook.apiClient.users_hasAppPermission(
                "status_update",
                function(result, exception)
                {
                    //alert(result);
                    if (result != true)
                    {
                        FB.Connect.showPermissionDialog(
                            "status_update",
                            function()
                            {
                                FB.Facebook.apiClient.users_setStatus(
                                    messageToPostToFacebook,
                                    false,
                                    true,
                                    function(result, exception) { /*if (result) { alert(result) }; if (exception) { alert(exception); }*/ }
                                );
                            });
                    }
                    else
                    {
                        FB.Facebook.apiClient.users_setStatus(
                            messageToPostToFacebook,
                            false,
                            true,
                            function(result, exception) { /*if (result) { alert(result) }; if (exception) { alert(exception); }*/ }
                        );
                    }
                });
        }

        // transmit the message
        DuckPond
        .Zuild
        .WebServer
        .Services
        .Chat
        .InsertMessage(
            this._RoomId,
            message,
            function(result) { This.SendMessageSuccess(result); },
            function(error) { This.SendMessageFailure(error); });

        // clear the textbox
        window.setTimeout(function() { This._TextBox_SendMsg.value = ""; }, 1);

        // set incoming messages panel to scroll to bottom
        if (this._InsertMessagesAtTop === false)
        {
            this._Panel_IncomingChat.scrollTop = this._Panel_IncomingChat.scrollHeight;
        }
        else
        {
            this._Panel_IncomingChat.scrollTop = 0;
        }
    },

    SendMessageSuccess: function(result)
    {
        if (!result == "")
        {
            alert(result);
        }

        // attempt to retrieve the messages we just sent
        this.NavigateToPage(1);
    },

    SendMessageFailure: function(error)
    {
        alert('Connection was lost while sending your message.');
    },

    ModerationShowHideMessage: function(messageId, jqMessageNode)
    {
        // do we need to hide it?
        if (jqMessageNode.data("ChatData")["IsHidden"] === false)
        {
            DuckPond
            .Zuild
            .WebServer
            .Services
            .Chat
            .ModerationHideMessage(
                messageId,
                function()
                {
                    //alert('Message succesfully hidden.');

                    // update client state
                    jqMessageNode.data("ChatData")["IsHidden"] = true;

                    // update client UI
                    jqMessageNode.find(".message").addClass("hiddenmessage");
                },
                function()
                {
                    alert('Network or server error. Please try again.');
                }
            );
        }
        // do we need to unhide it?
        else if (jqMessageNode.data("ChatData")["IsHidden"] === true)
        {
            DuckPond
            .Zuild
            .WebServer
            .Services
            .Chat
            .ModerationShowMessage(
                messageId,
                function()
                {
                    //alert('Message succesfully reshown.');

                    // update client state
                    jqMessageNode.data("ChatData")["IsHidden"] = false;

                    // update client UI
                    jqMessageNode.find(".message").removeClass("hiddenmessage");

                },
                function()
                {
                    alert('Network or server error. Please try again.');
                }
            );
        }
        // unexpected data
        else
        {
            alert('Unexepected message data found. Please report this.');
        }
    },

    ModerationBanUserByMessageId: function(messageId)
    {
        DuckPond
        .Zuild
        .WebServer
        .Services
        .Chat
        .ModerationBanUserByMessageId(
            messageId,
            function() { alert('User succesfully banned.'); },
            function() { alert('Network or server error. Please try again.'); }
        );
    }
};