﻿//The following is all the code necessary for the Conversations functionality in LinkPolonia
//Created by Cam, 19-24 March 2009

//Polls the server... not called directly, but rather, managed through IntelligentCalls() to
//minimize server impact.

var GetFriendsList = true; // the parameter that gets passed to the server about whether we care about friends list or not
var FriendsListIsVisible = false;
var ShowRandomUser = true;
var OnlineUsersTitle = '';
var ShowOnlineUsers = true;

function GetConversationMsg() {

    $('FriendListLoadingImg').style.display = '';
    if (openConv >= 0 && Users != null && Users[openConv] != null) {
        url = lp_root + '/Conversations.axd?a=get&u=' + myUsername + '&f=' + Users[openConv] + '&rd=' + Math.random() + '&fr=' + GetFriendsList + '&uid=' + myUserID;
    }
    else {
        //we don't have an open conversation, so just fake the active user to "a" which is a nonsense value
        url = lp_root + '/Conversations.axd?a=get&u=' + myUsername + '&f=a&rd=' + Math.random() + '&fr=' + GetFriendsList + '&uid=' + myUserID;
    }

    //random number differentiates the URL to keep it out of IE's cache... no comment
    $ajax(url, ProcessMessages);

    $('FriendListLoadingImg').style.display = 'none';
    GetFriendsList = false;
}

///Creates the actual markup for a conversation. Should NOT be called directly,
//it's used through Add-User.
function CreateConversation(id, name, firstname, picturePath) {
    var container = $('ConversationInnerContainer');

    var str = '<div class="Conversation" id="C' + id + '">';
    str += '<div class="ConversationTitle" id="ConversationTitle' + id + '">';
    str += '<a href="#" onclick="javascript:ToggleConversation(' + id + ');">' + firstname + '</a>';
    str += '</div>';
    str += '<div class="ConversationBox" id="Conversation' + id + '" style="display: none;">';
    str += '<div class="ConversationTop">';
    str += '<div class="ConversationTopName"><table style="width: 100%;"><tr><td style="width: 62px; text-align: center;"><img src="' + picturePath + '" /></td><td valign="middle" style="text-align: left;"><a href="' + lp_root + '/members/' + name + '.aspx">' + firstname + '</a></td></tr></table>';
    str += '</div>';
    str += '<div class="ConversationIcons">';
    str += '<img src=\"' + lp_root + '/Images/IM/close.png\" onclick="javascript:CloseConversation(' + id + ');" />';
    str += '<img src=\"' + lp_root + '/Images/IM/min.png\" onclick="javascript:HideConversation(' + id + ');" />';
    str += '</div>';
    str += '</div>';
    str += '<div class="ConversationContent" id="ConvContent' + id + '"></div>';
    str += '<div>';
    str += '<input type="text" maxlength="100" id="ConvMsg' + id + '" class="ConvMsg" onclick="javascript:RemoveBlink(' + id + ');" onkeydown=\"EnterKey(event, ' + id + ' )\" />';
    str += '<input type="button" value="' + l_Send + '" id="Send' + id + '" onclick="javascript:AddMessage(' + id + ');" class="ConvSendBtn" />';
    str += '</div>';
    str += '</div>';
    str += '</div>';

    container.innerHTML += str;

}

///Guess. 
function DestroyConversation(cid) {
    var container = $('ConversationInnerContainer');
    var n = 0;

    //because we might potentially have a user open and close windows like its going out of style,
    //we have to dig through the conversations looking for the one that matches.
    while (container.childNodes[n] != null) {
        if (container.childNodes[n].id == ('C' + cid)) {
            container.removeChild(container.childNodes[n]);
        }
        n++;
    }
    Users[cid] = '';
    Names[cid] = '';
    Statuses[cid] = '';

    var i = 0;
    for (i = 0; i < cBufferSize; i++) {
        cBuffer[cid][i] = '@@';
    }
}


document.defaultAction = true;

//bound to keypress on a conversation's textbox so that ENTER will send a message.
function EnterKey(e, id) {
    var evt = e || window.event;
    var keynum = evt.keyCode;
    if (keynum == 13) {
        AddMessage(id);
    }
    return document.defaultAction;
}

///self explanatory. called only on output.
function ParseEmoticons(msg) {
    msg = msg.replace(':)', '<img src=\"' + lp_root + '/Images/IM/happy.gif\" />');
    msg = msg.replace(':(', '<img src=\"' + lp_root + '/Images/IM/sad.gif\" />');
    msg = msg.replace(':D', '<img src=\"' + lp_root + '/Images/IM/grin.gif\" />');
    msg = msg.replace(':d', '<img src=\"' + lp_root + '/Images/IM/grin.gif\" />');
    msg = msg.replace(':\'(', '<img src=\"' + lp_root + '/Images/IM/cry.gif\" />');
    msg = msg.replace('(Y)', '<img src=\"' + lp_root + '/Images/IM/thumbsup.gif\" />');
    msg = msg.replace('(y)', '<img src=\"' + lp_root + '/Images/IM/thumbsup.gif\" />');
    msg = msg.replace('(N)', '<img src=\"' + lp_root + '/Images/IM/thumbsdown.gif\" />');
    msg = msg.replace('(n)', '<img src=\"' + lp_root + '/Images/IM/thumbsdown.gif\" />');
    msg = msg.replace(':p', '<img src=\"' + lp_root + '/Images/IM/tongue.gif\" />');
    msg = msg.replace(':P', '<img src=\"' + lp_root + '/Images/IM/tongue.gif\" />');
    msg = msg.replace('(a)', '<img src=\"' + lp_root + '/Images/IM/angel.gif\" />');
    msg = msg.replace('(A)', '<img src=\"' + lp_root + '/Images/IM/angel.gif\" />');
    msg = msg.replace('(6)', '<img src=\"' + lp_root + '/Images/IM/devil.gif\" />');
    msg = msg.replace(';)', '<img src=\"' + lp_root + '/Images/IM/wink.gif\" />');
    msg = msg.replace(':@', '<img src=\"' + lp_root + '/Images/IM/angry.gif\" />');
    msg = msg.replace('(u)', '<img src=\"' + lp_root + '/Images/IM/brokenheart.gif\" />');
    msg = msg.replace('(U)', '<img src=\"' + lp_root + '/Images/IM/brokenheart.gif\" />');
    msg = msg.replace('(l)', '<img src=\"' + lp_root + '/Images/IM/heart.gif\" />');
    msg = msg.replace('(L)', '<img src=\"' + lp_root + '/Images/IM/heart.gif\" />');
    msg = msg.replace('(k)', '<img src=\"' + lp_root + '/Images/IM/kiss.gif\" />');
    msg = msg.replace('(K)', '<img src=\"' + lp_root + '/Images/IM/kiss.gif\" />');
    msg = msg.replace(':s', '<img src=\"' + lp_root + '/Images/IM/confused.gif\" />');
    msg = msg.replace(':S', '<img src=\"' + lp_root + '/Images/IM/confused.gif\" />');
    msg = msg.replace('(*)', '<img src=\"' + lp_root + '/Images/IM/star.gif\" />');
    msg = msg.replace('(F)', '<img src=\"' + lp_root + '/Images/IM/rose.gif\" />');
    msg = msg.replace('(f)', '<img src=\"' + lp_root + '/Images/IM/rose.gif\" />');
    msg = msg.replace(':o', '<img src=\"' + lp_root + '/Images/IM/omg.gif\" />');
    msg = msg.replace(':O', '<img src=\"' + lp_root + '/Images/IM/omg.gif\" />');
    msg = msg.replace(':$', '<img src=\"' + lp_root + '/Images/IM/sheepish.gif\" />');
    return msg;
}
var OnlineFriendCount = 0;
var OnlineUserCount = 0;

///these are all dummy functions required by the sound player (which we keep empty so they don't do anything)
var myListener = new Object(); 
myListener.onInit = function() { this.position = 0; };
myListener.onUpdate = function() { }

///Handles data when it comes back from the server
function ProcessMessages(result) {
    var res = eval('(' + result.responseText + ')');
    var idx = 0;

    
    var playedSound = false;

    var FriendListBuffer = '';
    var OnlineCount = 0;

    var CheckingFriends = false;

    while (res != null && res[idx + ''] != null) {

        calls = 0; //reset our polling counter 
        var msg = res[idx];

        CheckingFriends = (msg["CheckingFriends"] != null && msg["CheckingFriends"].length > 0);
        if (msg["Type"] == "message") {
            //we only have a last name when its a friend's information... otherwise it's some sort of message

            var u = -1;
            if (msg["UserName"] != null && msg["UserName"].length > 0) {
                if (FindUser(msg["UserName"]) == -1) {
                    AddUser(msg["UserName"], msg["FirstName"], msg["PicturePath"]);
                }
                u = FindUser(msg["UserName"]);
            }


            if (msg["Message"] != null) {
                //we have a message to show

                if ((msg != null) && (!playedSound)) {
                    var sound = $('soundFlash');
                    try {
                        if (sound) {
                            //flash solution for sound playing is from http://flash-mp3-player.net/players/js/preview/
                            //player is created in BaseMasterPage.OnPreRender()
                            sound.SetVariable('method:setUrl', lp_root + '/sounds/beep.mp3');
                            sound.SetVariable('method:play', '');
                            sound.SetVariable('enabled', 'true'); 
                        }
                        playedSound = true;
                    }
                    catch (err) {
                        playedSound = true;
                    }
                }

                
                PrintMessage(u, msg["Message"], msg["FirstName"]);
            }
            else {
                //we just have a notification, so set the message to blink
                AddBlink(u);
            }
        }
        else if (ShowOnlineUsers != "False" && ShowOnlineUsers != "false" && msg["Type"] == "random") {
            var randUser = '<div>';
            randUser += '<div style="text-align: right; font-weight: bold;">' + OnlineUsersTitle + '&nbsp;&nbsp;<a href="#" onclick="javascript:$(\'SomeoneOnline\').style.display=\'none\';ShowRandomUser=false;return false;">[X]</a></div>';
            randUser += '<a href="' + lp_root + '/members/' + msg["UserName"] + '.aspx"><img style="border: 0;" src="' + lp_root + msg["PicturePath"] + '"><br>' + msg["Name"] + '</a>';
            randUser += '<div style="text-align: center;">';
            randUser += '<a href="#" onclick="javascript:startConversation(\'' + msg["UserName"] + '\',\'' + msg["FirstName"] + '\',\'' + msg["PicturePath"] + '\');"><img style="border: 0;" src="' + lp_root + '/Images/im.gif"></a>';
            randUser += '<a href="#" onclick="' + SendMsgClick.replace('[USERID]', msg["UserID"]) + '"><img style="border: 0;" src="' + lp_root + '/Images/mail_send.png"></a>';
            randUser += '</div>';
            randUser += '</div>';
            var randBox = $('SomeoneOnline');
            randBox.innerHTML = randUser;
            if (ShowRandomUser) {
                randBox.style.display = 'block';
            }
        }
        else if (msg["Type"] == "friend") {
            FriendListBuffer += '<li style="padding-left: 3px;"><a href=\"#\" onclick=\"javascript:startConversation(\'' + msg["UserName"].toLowerCase() + '\',\'' + msg["FirstName"].replace("'", "\\'") + '\',\'' + msg["PicturePath"] + '\');\">' + msg["FirstName"] + ' ' + msg["LastName"] + '</a></li>';
            OnlineFriendCount = msg["TotalCount"];
            OnlineCount++;
            $('FriendsList').style.display = '';
        }
        idx++;
    }

    if (FriendListBuffer.length > 1) {
        $('FriendListContent').innerHTML = '<ul style="list-style-position: outside; margin-left: 12px; padding-left: 0px;">' + FriendListBuffer + '</ul>';
        if (OnlineCount >= 10) {
            $('FriendListContent').innerHTML += '<a href=\"' + lp_root + '/MyFriends.aspx?Tab=1\" style=\"font-weight:bold\">' + SeeAll + ' (' + OnlineFriendCount + ')</a>';
        }
        UpdateFriendCountUI();
    }
    else if (CheckingFriends) {
        $('FriendListContent').innerHTML = NoFriendsOnline;
    }

    SaveStatus();
}

function EscapeMsg(m) {
    m = m.replace(/ó/g, '7770243');
    m = m.replace(/Ó/g, '7770211');
    m = escape(m);
    return m;
}
function UpdateFriendCountUI() {
    if (OnlineFriendCount > 0) {
        $('OnlineFriendCount').innerHTML = ' - (' + OnlineFriendCount + ')';
    }
    else {
        $('OnlineFriendCount').innerHTML = '';
    }
    if (FriendsListIsVisible) {
        $('FriendsList').style.display = '';
    } else {
        $('FriendsList').style.display = 'none';
    }
}

var TooManyUsersErr = '';
var SeeAll = '';
var curConv = null;
var curConvTitle = null;
var myName = null;
var myUsername = '';
var myUserID = '';
var Blinkers = '';

//Adds a conversation to the list of conversations that are blinking
function AddBlink(id) {
    if (id >= 0 && Blinkers.indexOf(id) == -1) {
        Blinkers += 'ConversationTitle' + id + '$';
    }
}

///Removes a conversation from the list of conversations that are blinking
function RemoveBlink(id) {
    Blinkers = Blinkers.replace('ConversationTitle' + id + '$', '');
    var element = $('ConversationTitle' + id);
    element.className = element.className.replace(' Blink', '');
}

var BlinkOn = true;
///Does what you'd think, runs through a list of controls to make "blink" and flips
//their CSS classes appropriately.
function Blink() {
    var toBlink = Blinkers.split('$');
    var i;

    BlinkOn = !BlinkOn;

    for (i = 0; i < toBlink.length; i++) {
        if (toBlink[i].length > 0) {
            var element = $(toBlink[i]);
            if (element != null) {
                if (!BlinkOn) {
                    element.className = element.className.replace(' Blink', '');
                } else {
                    element.className += ' Blink';
                }
            }
        }
    }
}

//Called on page creation to initialize the buffer so it can be used properly later
function InitBuffer(size) {
    var a = new Array(size);
    var i;
    for (i = 0; i < a; i++) {
        a[i] = '@@';
        //we init each spot to an empty set of quotes for parsing reasons given the string <-> matrix 
        //conversions required when dealing with cookies.
    }
    return a;
}

///Gives focus to a conversation's text entry box (called on click)
function GiveFocus(conv) {
    $('ConvMsg' + conv).focus();
    RemoveBlink(conv);
}


//we want to end up with a bufferarray of B[C][M]... where C represents
//the conversation number and M represents the message number

var cBufferSize = 3; //how many messages do we store in each buffer?
var cBufferCount = 7; //how many buffers do we have?

var cookieName = 'cBuffer';

var cBuffer0 = InitBuffer(cBufferSize);
var cBuffer1 = InitBuffer(cBufferSize);
var cBuffer2 = InitBuffer(cBufferSize);
var cBuffer3 = InitBuffer(cBufferSize);
var cBuffer4 = InitBuffer(cBufferSize);
var cBuffer5 = InitBuffer(cBufferSize);
var cBuffer6 = InitBuffer(cBufferSize);

var cBuffer = new Array(cBufferCount);
//message buffer
var Statuses = new Array(cBufferCount);
//whether a given window is open or closed
var Users = new Array(cBufferCount);
//usernames we are currently talking with
var Names = new Array(cBufferCount);
//first names of the same people (must be kept consistent with Users)
var PicPaths = new Array(cBufferCount);
//picture paths of the same people (added July 8 2009)

cBuffer[0] = cBuffer0;
cBuffer[1] = cBuffer1;
cBuffer[2] = cBuffer2;
cBuffer[3] = cBuffer3;
cBuffer[4] = cBuffer4;
cBuffer[5] = cBuffer5;
cBuffer[6] = cBuffer6;

setInterval("Blink()", 500); //somewhat self explanatory, i hope

var openConv = 0;

function initConversation(cID) {
    curConv = $('Conversation' + cID);
    curConvTitle = $('ConversationTitle' + cID);
    Statuses[openConv] = 'C';
    Statuses[cID] = 'O';
    openConv = cID;
    //set the existing open conv to Closed... and the one we want to open to Open
    //then remember which one we're working on now so we can repeat this in the future
}

///Shows the specified conversation, as well as hiding the last one to be shown so that
//we never show two at once. Finally, it updates the tracker so that we'll close this one
//next time without having to look for it.
function showConversation(cID) {



    var id;
    if (curConv != null) {
        id = curConv.id;
        if ($(id) != null) {
            $(id).style.display = 'none';
            $(curConvTitle.id).className = 'ConversationTitle';
        }
    }
    initConversation(cID);
    if (curConv != null) {
        curConv.style.display = '';
        Statuses[cID] = 'O';

        var le = FindLeftEdge($('ConversationTitle' + cID));
        curConv.style.right = (10 + document.documentElement.clientWidth - (152 + le)) + 'px';
        //we align the current conversation box with its "heading" in the conversation bar
        curConvTitle.className = 'ConversationTitleSelected';
        RemoveBlink(cID);
        SaveStatus();
        GiveFocus(cID);
        GetConversationMsg();
        calls = 0; //we changed windows, that's enough to keep polling "quickly"
    }
}

///This is how we initialize a new conversation with a user.
function AddUser(username, firstname, picPath) {

    var n = 0;
    username = username.toLowerCase();
    while (Users[n] != null && Users[n].length > 0 && Users[n] != username) {
        n++;
    }
    if (n >= Users.length) {
        return -2; //too many damn conversations. get out.
    }
    var idx = FindUser(username);
    if (idx == -1) { //if the user is not found, we need to add them
        Users[n] = escape(username);
        Names[n] = escape(firstname);
        PicPaths[n] = escape(picPath);
        CreateConversation(n, username, firstname, picPath);
    }
    if (n == 0 && Statuses[0] != 'C') { //if this is the first conversation, then show it.
        showConversation(0);
    }

}
//removes a user from the list of those we are currently tracking messages from
function RemoveUser(username) {
    var n;
    username = username.toLowerCase();
    for (n = 0; n < cBufferCount; n++) {
        if (Users[n] == username) {
            Users[n] = '';
            Names[n] = '';
        }
    }
}

///Finds the ID of the conversation with the user represented by the username passed in
function FindUser(username) {
    var n;
    username = username.toLowerCase();
    for (n = 0; n < cBufferCount; n++) {
        if (Users[n] == username) {
            return n;
        }
    }
    return -1;
}
function EmptyFunction(result) {
    //exists merely to fill callback with proper and empty function
}

//Adds a message to the conversation buffer (this essentially handles SendBtn_Click)
//also sends it to the server, clears the window, and saves our current status
function AddMessage(conv) {
    var input = $('ConvMsg' + conv);
    var msg = "";
    if (input != null && input.value.length > 0) {
        var str = input.value.replace(/^\s+|\s+$/g, '');
        if (str.length > 0) {
            msg = input.value;
            input.value = '';
        }
    }

    if (msg.length > 0) {
        PrintMessage(conv, msg);
        SaveStatus();
        RemoveBlink(conv);

        calls = 0; //reset our polling counter 

        url = lp_root + '/Conversations.axd?a=add&u=' + myUsername + '&f=' + myName + '&r=' + Users[conv] + '&m=' + EscapeMsg(msg) + '&rd=' + Math.random() + '&pp=' + myPicturePath;
        $ajax(url, EmptyFunction);
    }
}

///Prints a message to the screen and to the buffer. 
function PrintMessage(conv, msg, name, fromBuff) {
    if (msg != null && msg.length > 0) {
        var myMsg = (name == null); //its my message if we don't 
        if (name == null) {
            name = myName;
        }

        //we generate a local timestamp for the message...
        //then we save it into the buffer, and output it onto the screen if we DID NOT come from the buffer
        //if we came from the buffer, its built into the message already.
        var d = new Date();
        var timestamp = d.getHours() + ':';
        if ((d.getMinutes() + '').length == 1) {
            timestamp = timestamp + '0' + d.getMinutes();
        }
        else {
            timestamp = timestamp + d.getMinutes();
        }

        
        if (Statuses[conv] != 'O' && !initialLoad) { AddBlink(conv); }
        cBuffer[conv][0] = cBuffer[conv][1];
        cBuffer[conv][1] = cBuffer[conv][2];

        //not printing from buffer, so add timestamp to message ... which means it will get printed out
        //correctly, and be added to the buffer and hence, remembered for the next page
        if (!fromBuff) {
            msg = '- <b>' + timestamp + '</b> - ' + msg;        
        }
        
        //we need to store the message with a flag (the | character) to distinguish between what i said and what they said
        //when we're reloading the buffer from the cookie
        if (myMsg) {
            cBuffer[conv][2] = '@' + escape(msg) + '@';
        } else {
            cBuffer[conv][2] = '@|' + escape(msg) + '@';
        }


        //we wrap the message in quotes because commas in a message would cause spectacular failure if we didn't
        var c = $("ConvContent" + conv);
        if (c != null && msg != '@@') {
            
            msg = msg.replace(/7770243/g, 'ó');
            msg = msg.replace(/7770211/g, 'Ó');
            if ((c.childNodes.length & 1) == 0) {
                c.innerHTML += '<p><b>' + name + '</b>: ' + ParseEmoticons(msg) + '</p>';
            }
            else {
                c.innerHTML += '<p class=\"alt\"><b>' + name + '</b>: ' + ParseEmoticons(msg) + '</p>';
            }
            c.scrollTop = c.scrollHeight; //scrolls to bottom of div.
        }

    }
}

function DoSave() {
    var i = 0;
    for (i = 0; i < cBufferSize; i++) {
        if (Users[i] != null && Users[i].length > 0) {
            return true;
        }
    }
    return false;
}
///Saves the entire current status of the chat application to a cookie so it can be remembered.
function SaveStatus() {
    var status = MatrixToString(cBuffer, cBufferCount, cBufferSize) + 'DELIM' + Statuses + 'DELIM' + Users + 'DELIM' + Names + 'DELIM' + PicPaths;


    if (DoSave()) {
        createCookie(cookieName, status);
    }
    else {
        eraseCookie(cookieName);
    }
}

///Loads the current status of the chat application from the cookie
function LoadStatus() {
    var val = readCookie(cookieName);
    var tempUsers = Array(cBufferSize);
    var tempNames = Array(cBufferSize);
    var tempPaths = Array(cBufferSize);
    if (val != null && val.length > 0) {
        var status = val.split('DELIM');

        if (status[1] != null && status[1].length > 0) {
            Statuses = status[1].split(',');
        }
        if (status[2] != null && status[2].length > 0) {
            tempUsers = status[2].toLowerCase().split(',');
        }
        if (status[3] != null && status[3].length > 0) {
            tempNames = status[3].split(',');
        }
        if (status[4] != null && status[4].length > 0) {
            tempPaths = status[4].split(',');
        }
        //recreate the conversations
        var i = 0;
        for (i = 0; i < tempUsers.length; i++) {
            if (tempUsers[i] != null && tempUsers[i].length > 0) {
                AddUser(unescape(tempUsers[i]), unescape(tempNames[i]), unescape(tempPaths[i]));
            }
            if (Statuses[i] == 'O') {
                openConv = i;
                showConversation(i);
            }
        }
        //refill the conversations now that they exist again
        LoadFromBuffer(status[0]);
    }
}

var initialLoad = false;
//loads the most recent messages from the cookie... relies on the conversation
//windows already existing through Add-User calls
function LoadFromBuffer(b) {
    var newArray = StringToMatrix(b, cBufferCount, cBufferSize);
    var conv, msg;
    initialLoad = true;
    if (newArray != null) {
        for (conv = 0; conv < cBufferCount; conv++) {
            if (newArray[conv] != null) {
                for (msg = 0; msg < cBufferSize; msg++) {
                    if (newArray[conv][msg] != null) {
                        var temp = newArray[conv][msg];
                        if (temp != undefined && temp.length > 0) {
                            if (temp.charAt(0) == '|') {
                                //the message is from the OTHER user
                                //take out the flag and then print the message to the screen
                                temp = temp.substring(1, temp.length);
                                PrintMessage(conv, unescape(temp), unescape(Names[conv]), true);
                            }
                            else {
                                //the message is my own
                                PrintMessage(conv, unescape(temp), null, true);
                            }
                        }
                    }
                }
            }
        }
    }
    initialLoad = false;

}

///Converts a matrix of size a[X][Y] to a string of comma separated values... empty strings
///are represented by the literal "" for parsing reasons in the converse function to this.
function MatrixToString(arr, x, y) {
    var i, j;
    var str = '';
    for (i = 0; i < x; i++) {
        for (j = 0; j < y; j++) {
            if (arr[i][j] != null) {
                str += '@' + arr[i][j] + '@,';
            } else {
                str += '@@,';
            }
        }
    }
    return str.substr(0, str.length - 1);
}
///Converts a string to a matrix, or an array of arrays. We end up with
///a matrix composed of X arrays of Y length.
function StringToMatrix(str, x, y) {
    var i, j;
    var arr = new Array(x);

    if (str != null && str.length > 0) {

        //split the string passed in into a flat array 1 by (X * Y) elements in size
        var strarr = str.split('@,@');

        ///because we split on three characters, the first and last message will have
        ///an extra quote artifact to strip. 
        if (strarr[0].length > 0) {
            strarr[0] = strarr[0].substr(1);
        }
        var last = (x * y) - 1;
        if (strarr[last] != null && strarr[last] != length > 0) {
            strarr[last] = strarr[last].substr(0, strarr[last].length - 1);
        }

        //now we're going to loop through the array and convert it into a matrix
        //as complicated as this looks, it's just math. The first Y elements are the first array,
        // Y+1 through 2Y is the second array, etc.
        for (i = 0; i < x; i++) {

            arr[i] = new Array(y);

            for (j = 0; j < y; j++) {

                var idx = (i * y) + j;

                //if we have more then two characters, there's an actual message, so let's
                //take the quote off the beginning and the end of it.
                if (strarr[idx] != null && strarr[idx].length > 0) {
                    arr[i][j] = strarr[idx].substr(1, strarr[idx].length - 2);
                } else {
                    //otherwise we can just leave it as is, its essentially an empty string anyway
                    arr[i][j] = strarr[idx];
                }
            }
        }
    }
    return arr;
}

var calls = 0;
function IntelligentCalls() {

    GetFriendsList = (calls % 10 == 0);

    if (calls < 5 || (calls % 5 == 0 && calls < 50) || (calls % 20 == 0 && calls < 300)) {
        //we call the server in three cases
        //1. the first five times we do this
        //2. Every 5 times after that until it's been 50 times (ie. 5, 10, 15, 20, 25, etc.)
        //3. Every 20 times after that (70, 90, 110, etc.)
        //this counter is also reset every time we have a message
        GetConversationMsg();
    }

    calls++;
}

var baseDomain = '';
var NoFriendsOnline = '';
var SendMsgClick = '';


//Initialization function that gets everything else going.
function startConversations(name, username, lang, domain, userID, showOU, sendPM) {
    myName = name;
    myUsername = username.toLowerCase();
    myUserID = userID;
    baseDomain = domain;
    ShowOnlineUsers = showOU;
    SendMsgClick = sendPM;
    cookieName += username; //making sure we have a distinct username

    var isIE6 = /msie|MSIE 6/.test(navigator.userAgent);
    if (isIE6) {
        $addScroll(HandleScrollIE6);
    }
    if (lang.toLowerCase() == 'pl-pl') {
        TooManyUsersErr = 'Już rozmawiasz z maksymalną ilością znajomych.';
        SeeAll = 'Zobacz wszystkich znajomych';
        OnlineUsersTitle = 'Zalogowani';
        NoFriendsOnline = 'Nie ma zalogowanych znajomych.';
    }
    else {
        TooManyUsersErr = 'You are already talking to the maximum number of people.';
        SeeAll = 'See All Friends';
        OnlineUsersTitle = 'Online Users';
        NoFriendsOnline = 'No friends are currently online.';
    }
    if (username != null && username.length > 0) {

        UpdateFriendCountUI();


        //load our status and all that
        LoadStatus();

        setInterval("IntelligentCalls()", 6000);
    }
}

function HandleScrollIE6() {
    var CC = $('ConversationOuterContainer');
    if (CC != null) {
        CC.style.top = (document.documentElement.clientHeight + document.documentElement.scrollTop - 20) + "px";
        CC.style.left = '0px';
    }
}
///wrapper so the markup within LP itself has a name that makes sense in a more generic context
function startConversation(username, firstname, picpath) {
    username = username.toLowerCase();
    var cid = FindUser(username);
    var result = 0;
    if (cid == -1) {
        result = AddUser(username, firstname, picpath);
    }
    if (result == -2) {
        alert(TooManyUsersErr);
    }
    else {
        cid = FindUser(username);
        showConversation(FindUser(username));
    }
    return false;
}

//"minimizes" a particular conversation
function HideConversation(cid) {
    $('Conversation' + cid).style.display = 'none';
    $('ConversationTitle' + cid).className = 'ConversationTitle';
    openConv = -1;
    Statuses[cid] = 'C';
    SaveStatus();
}

///Gets rid of a particular conversation
function CloseConversation(cid) {
    DestroyConversation(cid);

    if (Users[0] != null && Users[0].length > 0) {
        showConversation(0); //show the first conversation if there is one
    }
    SaveStatus();
}

///finds the left edge of a control, used for positioning conversation windows
function FindLeftEdge(obj) {
    var curleft = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
        } while (obj = obj.offsetParent);
    }
    return curleft;
}


function createCookie(name, value, days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = "; expires=" + date.toGMTString();
    }
    else var expires = "";
    document.cookie = name + "=" + value + expires + "; path=/; domain=." + baseDomain + ";";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) {
            return c.substring(nameEQ.length, c.length);
        }
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name, "", -1);
}
function ToggleFriendsList() {
    FriendsListIsVisible = !FriendsListIsVisible;

    if (FriendsListIsVisible) {
        ShowFriendsList();
    }
    else {
        CloseFriendsList();
    }
}
function ShowFriendsList() {

    //anything under 5 is a nonsense value... since empty strings have length 1 apparently, we're giving ourselves a margin for error
    var doCall = ($('FriendListContent').innerHTML.length < 5);
    FriendsListIsVisible = true;
    GetFriendsList = true;
    $('FriendsList').style.display = '';
    if (doCall) {
        GetConversationMsg();
    }
    SaveStatus();
}

function CloseFriendsList() {
    $('FriendsList').style.display = 'none';
    FriendsListIsVisible = false;
    SaveStatus();
}

function ToggleConversation(cid) {
    if (Statuses[cid] == 'O') {
        HideConversation(cid);
    }
    else {
        showConversation(cid);
    }
}

function ServerOFC(friendcount, usercount) {
    OnlineFriendCount = friendcount;
    OnlineUserCount = usercount;
}
