﻿/// <reference path="jquery-1.3.2-vsdoc.js" />
//
// e-office webchat 1.0, http://microsoft.e-office.com
//
(function($) {
    //
    // plugin definition
    //
    $.fn.webchatStatus = function(licenseId, options) {

        var sessionId = '';

        var messages;
        var profile;
        var input;
        var content;

        var chatTimerIntervalDefault = 1500;
        var chatTimerInterval = 0;
        var presenceTimerIntervalDefault = 6000;
        var presenceTimerInterval = 0;
        var onlinePresence = 3500;
        var conversationState = 0;
        var presenceState = 0;
        var chatResponseCount = 0;
        var presenceResponseCount = 0;
        var errorPresence = -1;
        var jsonP = "?method=?";

        var opts = $.extend({}, $.fn.webchatStatus.defaults, options);

        return this.each(function() {
            $this = $(this);
            // build element specific options
            var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
            o.licenseId = licenseId;

            buildChatWindowStatus($(this));
            
            startConnection();

            return $(this);
        });

        function buildChatWindowStatus(elem) {
            $(elem).addClass("webchatStatus");

            profile = $("<div/>")
                .addClass("profile")
                .addClass("availableText")
                .appendTo($(elem));

//            $(profile).append($("<div/>").addClass("picture"));
//            $(profile).find("div.picture").append("<div class='typing'>" + opts.nowTyping + "</span>");
//            $(profile).find("div.picture").append("<img alt=''>");
            var p = $("<div/>").addClass("persona").appendTo($(profile));
//            $(p).append($("<div/>").addClass("name"));
//            $(p).append($("<div/>").addClass("email").append("<a>"));
            $(p).append($("<div/>").addClass("availableText"));

            content = $("<div/>").addClass("content").appendTo($(elem));

           // messages = $("<div/>").addClass("messages").appendTo($(content));
            //input = $("<div/>").addClass("input").append("<textarea>").appendTo($(content));

//////            $(input).find("textarea").html(opts.emptyInputText)
//////            .focus(function() {
//////                if ($(this).html() == opts.emptyInputText)
//////                    $(this).html('');
//////            })
//////            .blur(function() {
//////                if (conversationState == 0 && $(this).html().length == 0)
//////                    $(this).html(opts.emptyInputText)
//////            });
//////            $(input).find("textarea").keydown(keyDownInput);

            if (opts.collapsed) {
                $(content).hide();
                $(profile).addClass("profileCollapsed");
            }
            if (opts.showEmail)
                $(p).find("div.email").show();
            else
                $(p).find("div.email").hide();

            if (opts.showAvailableText) {
                $(p).find("div.availableText").html(opts.unavailableText).show();
                $(profile).click(function() {
                    if (opts.collapsed) {
                        opts.collapsed = false;
                        $(content).show();
                        $(profile).removeClass("profileCollapsed")
                    }
                    else {
                        opts.collapsed = true;
                        $(content).hide();
                        $(profile).addClass("profileCollapsed")
                    }

                });
            }
            else
                $(p).find("div.availableText").hide();
        }

        function startConnection() {

            $.getJSON(opts.webserviceUrl + opts.licenseId + opts.connectMethod + opts.identifier + "/" + Base64.encode(opts.data) + jsonP
                ,
               function(data) {
                   sessionId = data.ConnectJsonResult;
                   if (sessionId.length > 0 && sessionId != "-1")
                       presenceReceive();
                   else {
                       setPresence('', '', '', errorPresence);
                   }
               }
           );

        }

        function startChatTimer() {
            if (chatResponseCount < 2)
                chatTimerInterval = chatTimerIntervalDefault;
            else if (chatResponseCount >= 2 && chatResponseCount < 4)
                chatTimerInterval = chatTimerIntervalDefault * 2;
            else
                chatTimerInterval = chatTimerIntervalDefault * 3;

            window.setTimeout(chatReceive, chatTimerInterval);
        }

        function startPresenceTimer() {
            if (presenceResponseCount < 8)
                presenceTimerInterval = presenceTimerIntervalDefault;
            else
                presenceTimerInterval = presenceTimerIntervalDefault * 2;

            window.setTimeout(presenceReceive, presenceTimerInterval);
        }

        function presenceReceive() {
            if (sessionId == "")
                startConnection();

            $.getJSON(opts.webserviceUrl + opts.licenseId + opts.receivePresenceMethod + sessionId + jsonP,
                function(response) {
                    if (response.ReceivePresenceDataJsonResult != null) {
                        setPresence(response.ReceivePresenceDataJsonResult.DisplayName,
                           response.ReceivePresenceDataJsonResult.Email,
                           response.ReceivePresenceDataJsonResult.ProfilePictureUrl,
                           response.ReceivePresenceDataJsonResult.Presence);
                        presenceResponseCount++;
                        startPresenceTimer();
                    }
                }
            );
        }

        function setPresence(name, email, image, presence) {
            $(profile).find("div.name").html(name);
            var p = $(profile).find("div.picture img");
            var i = $(input).find("textarea");
            if (image != p.attr("src"))
                p.attr('src', image);
            p.removeClass("error");
            if (presence == onlinePresence) {
                p.removeClass("offline");
                p.addClass("online");
                i.removeAttr("disabled");
                $(profile).find("div.availableText").addClass("available").removeClass("unavailable").html(opts.availableText);
                if (i.html() == opts.offlineText)
                    i.html(opts.emptyInputText);
            }
            else if (presence == errorPresence) {
                p.removeClass("online");
                p.addClass("error");
                i.attr("disabled", "disabled");
                $(profile).find("div.availableText").addClass("unavailable").removeClass("available").html(opts.unavailableText);

                if (i.html().length == 0 || i.html() == opts.emptyInputText)
                    i.html(opts.errorText);
            }
            else {
                p.removeClass("online");
                p.addClass("offline");
                $(profile).find("div.availableText").addClass("unavailable").removeClass("available").html(opts.unavailableText);

                i.attr("disabled", "disabled");
                //if (i.html().length == 0 || i.html() == opts.emptyInputText)
                //    i.html(opts.offlineText);
            }
            presenceState = presence;
            var e = $(profile).find("div.email a");
            e.html(opts.emailLink);
            if (email == '' || opts.showEmail == false)
                e.hide();
            else {
                e.attr("href", "mailto:" + email).show();
            }
        }

        function chatReceive() {
            if (sessionId == "")
                startConnection();

            $.getJSON(opts.webserviceUrl + opts.licenseId + opts.receiveDataMethod + sessionId + jsonP,
                {},
               function(response) {
                   if (response.ReceiveChatDataJsonResult != null) {
                       switch (response.ReceiveChatDataJsonResult.State) {
                           case 5:
                               // Message
                               addMessage(response.ReceiveChatDataJsonResult.Message, $(profile).find("div.name").html(), new Date(), 1, messages);
                               break;
                           case 1:
                               //
                               showTypingIndicator();
                               break;
                           default:
                               //
                               hideTypingIndicator();
                               break;
                       }
                       chatResponseCount = 0;
                   }
                   else
                       chatResponseCount++;

                   if (conversationState == 1)
                       startChatTimer();
               }
            );
        }

        function showTypingIndicator() {
            $(profile).find("div.typing").show();
        }

        function hideTypingIndicator() {
            $(profile).find("div.typing").hide();
        }

        function keyDownInput(event) {
            var cbinput = $(this);
            if (event.keyCode == 13 && event.shiftKey == 0) {
                message = $(cbinput).val();
                message = message.replace(/^\s+|\s+$/g, "");

                $(cbinput).val('');
                $(cbinput).focus();
                if (message != '') {
                    if (conversationState == 0) {
                        debug('Starting conversation');
                        $.getJSON(opts.webserviceUrl + opts.licenseId + opts.startConversationMethod + sessionId + jsonP,
                                { displayName: opts.displayName, subject: opts.subject, data: opts.data, message: message }
                            ,
                            function(response) {
                                sessionId = response.StartConversationJsonResult;
                                conversationState = 1;
                                startChatTimer();
                            }
                        );
                    }
                    else {
                        debug('Sending message');
                        $.getJSON(opts.webserviceUrl + opts.licenseId + opts.sendMessageMethod + sessionId + jsonP,
                                { message: message }
                            ,
                            function(response) {
                                if (response.Detail == "No conversation exists for this connection.") {
                                    conversationState = 0;
                                }
                            }
                        );

                    }

                    // Add message to window
                    addMessage(message, opts.displayName, new Date(), 0, messages);

                    chatResponseCount = 0;
                }

                return false;
            }
        }

        function addMessage(message, username, timestamp, direction, container) {
            message = escapeHTML(message);
            message = generateLinks(message);
            var d = new Date(timestamp);
            var hours = d.getHours();
            var minutes = d.getMinutes();

            if (minutes < 10)
                minutes = "0" + minutes;

            var ts = hours + ":" + minutes;
            var mes = $("<div/>").addClass("message").fadeIn("slow").appendTo(container);
            if (direction == 0)
                $(mes).addClass("out");
            else
                $(mes).addClass("in");

            $("<div/>").addClass("title").html(username + opts.nameTimeSeperator + ts).appendTo(mes);
            $("<div/>").addClass("msg").html(message).appendTo(mes);
            $(container).scrollTop($(container)[0].scrollHeight);
        }

        function escapeHTML(s) {
            return (
            s.replace(/&/g, '&amp;').
                replace(/>/g, '&gt;').
                replace(/</g, '&lt;').
                replace(/"/g, '&quot;').
                replace('\n', '<br />')
             );
        }

        function generateLinks(text) {
            if (!text) return text;

            text = text.replace(/((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi, function(url) {
                nice = url;
                if (url.match('^https?:\/\/')) {
                    nice = nice.replace(/^https?:\/\//i, '')
                }
                else
                    url = 'http://' + url;

                return '<a target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>';
            });

            return text;
        }


    };

    $.fn.webchatStatus.getGroups = function(licenseId, callback) {
        $.getJSON($.fn.webchatStatus.defaults.webserviceUrl + licenseId + $.fn.webchatStatus.defaults.getGroupsMethod + "?method=?",
        function(data) {
            if (callback)
                callback(data);
        });
        return this;
    }

    $.fn.webchatStatus.getGroup = function(licenseId, identifier, callback) {
        $.getJSON($.fn.webchatStatus.defaults.webserviceUrl + licenseId + $.fn.webchatStatus.defaults.getGroupMethod + identifier + "?method=?",
        function(data) {
            if (callback)
                callback(data);
        });
        return this;
    }

    //
    // private function for debugging
    //
    function debug($obj) {
        if (window.console && window.console.log)
            window.console.log($obj);
    };

    /**
    *
    *  Base64 encode / decode
    *  http://www.webtoolkit.info/
    *
    **/

    var Base64 = {

        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

        // public method for encoding
        encode: function(input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = Base64._utf8_encode(input);

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

            }

            return output;
        },

        // private method for UTF-8 encoding
        _utf8_encode: function(string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++) {

                var c = string.charCodeAt(n);

                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }

            return utftext;
        }
    }

    //
    // plugin defaults
    //
    $.fn.webchatStatus.defaults = {
        webserviceUrl: 'http://82.94.160.10/webchat/v1.2/webchatrest.svc/',
        startConversationMethod: '/chat/start.json/',
        sendMessageMethod: '/chat/message.json/',
        connectMethod: '/connect.json/',
        receiveDataMethod: '/chat/data.json/',
        receivePresenceMethod: '/presence.json/',
        getGroupsMethod: '/groups.json',
        getGroupMethod: '/group.json/',
        identifier: 'identifier',
        subject: 'webchat request',
        displayName: 'webuser',
        data: 'DocumentUri=' + location.href,
        emailLink: 'email',
        nowTyping: '&nbsp;',
        nameTimeSeperator: ' - ',
        emptyInputText: 'type here to start chatting',
        offlineText: 'currently there is no one online to chat',
        errorText: 'there was an error connecting to the service',
        collapsed: false,
        showEmail: true,
        showAvailableText: false,
        availableText: 'is available for a chat',
        unavailableText: 'is unavailable for a chat'
    };

    //
    // end of closure
    //
})(jQuery);

