// JScript source code

var userAgent = navigator.userAgent.toLowerCase();
//alert(userAgent);
var isIE = (userAgent.indexOf('msie') != -1);
var isFF = (userAgent.indexOf('firefox') != -1);
var isWK = (userAgent.indexOf('webkit') != -1);
var sURIFUIDIR2 = '';

if (window.sFUIDIR === undefined)
{
    sFUIDIR = ''; sFUIDIR2 = '';
}
else
{
    sFUIDIR2 = sFUIDIR + '/';
    var sTPN = window.location.pathname.replace(/chatui.aspx/i, "");
    var hostport = ":" + window.location.port;
    sURIFUIDIR2 = "http://" + window.location.hostname + hostport + sTPN + sFUIDIR2;
}

var aaTagged = new Array();

var sMsg = '';
//var sIcoDir = (isWK)? sFUIDIR + '/Chat_files/listicons/' : 'Chat_files/listicons/';
var sIcoDir = 'Chat_files/listicons/';
var sIcoDir2 = 'Chat_files/listicons/';
var arListIcons = new Array();
arListIcons["ico_spect"] = 'spect.gif';
arListIcons["ico_away"] = 'away.gif';
arListIcons["ico_nogender"] = 'nogender.gif';
arListIcons["ico_nogenderwpic"] = 'nogenderwpic.gif';
arListIcons["ico_female"] = 'female.gif';
arListIcons["ico_femalewpic"] = 'femalewpic.gif';
arListIcons["ico_male"] = 'male.gif';
arListIcons["ico_malewpic"] = 'malewpic.gif';
arListIcons["ico_spacer"] = 'noprofile.gif';
arListIcons["ico_staff"] = 'staff.gif';
arListIcons["ico_superowner"] = 'superowner.gif';
arListIcons["ico_owner"] = 'owner.gif';
arListIcons["ico_ignore"] = 'ignore.gif';
arListIcons["ico_host"] = 'host.gif';
arListIcons["ico_helpop"] = 'helpop.gif';
arListIcons["ico_tagged"] = 'tagged.gif';
arListIcons["ico_servicerm"] = 'rmicon_srv.jpg';
arListIcons["ico_regrm"] = 'rmicon_user.jpg';

var ptxSend = null;
var pChatPane = null;
var pwndGLD = null, ptxGLN = null, ppwGuest = null, ptxGLDErrorMessage = null;
var olvUsers = null;
var flashObj = null; idIntIsWbrLoadedPtr = 0;
var IsGuestInfoSet = false;
var plbMe = null, puicoMe = null, ouserMe = null, cmnuSelMe = false; var flashsckloaded = false; var strGuestPass = '';
var m_sChan = '', pchanIco = null, ptxChan = null, ptxChanModes = null, ptxNumberOfUser = null;
var dMyDate = new Date();
var FlashWindowEnabled = false;

var paturl = "https?://(\\w*:\\w*@)?[-\\w.]+(:\\d+)?(/([^\\s[]*(\\?[^\\s]+)?)?)?", pattag = "<.*?>|\\[style .*?\\]|\\[\/.*?\\]|\\[br\\]|<|>";
var reHTMLFRMTTAGS = /\bspan\b|\bfont\b|\bb\b|\bi\b|\bu\b/i;
var reInlineScript = /\son\w.*?=/i;
var reBBCODES = /\[style.*?\]|\[\/style\]/i;
var reBBCODES_SUB = /ff:.+?;|co:.+?;|bgco:.+?;|b;|i;|u;|\bundefined\b/ig;
var aTagNeedClosing = new Array();
var re = null;

var tmpUser = new Object();
tmpUser.pUser = { nick:null, ident:null, host:null, ilevel:0, iprofile:NoProfile, away:false, awaymsg:"", voice:false, tagged:false };
var sDspFrmt = '', bCorpText = true;
var sAwayMsg = '';
var bDspArrivals = true, bDspStatusChg=true, bDspDeparts=true;
var bSndArrival = true, bSndKick = true, bSndTagged = true, bSndInvites = true, bSndWhisp = true;
var bEmotsOff = false, bTextFrmtOff = false;
var bWhispOff = false, bTimeStampOn = false;
var XmlNullChar = '$1a2XMLNULL2a1$';

var IsStaff = 128, IsSuperOwner = 64, IsOwner = 32, IsHost = 16, IsHelpOp = 8;
var NoProfile = 0, NoGender = 1, NoGenderWPic = 2, Female = 3, FemaleWPic = 4, Male = 5; MaleWPic = 6;

var Is_m_Mode = false, Is_x_Mode = false;
var Modes = new Array(5); Modes[0] = Modes[1] = Modes[2] = Modes[3] = Modes[4] = "";

var KEY_UP = 38, KEY_DOWN = 40, KEY_BACKSPACE = 8;
var UPDATEUSER_TEXT = 0, UPDATEUSER_FORMATING = 1, UPDATEUSER_ICON = 2, UPDATEUSER_ICON2 = 3;
var WHISP_IN = 1, WHISP_OUT = 2;

var USER_GUEST = 0, USER_REG = 1;

var CMD_KICK = 0, CMD_KICKBAN15M = 1, CMD_KICKBAN1H = 2, CMD_KICKBAN24H = 3;

var sSiteURL = '';
var iUserLoggin = 0;

var MChatPaneLines = 0, MChatPaneMaxLines = 250;
var MChatPaneTemp = "";

//<Untility Functions>

function DebugWhisp(loc, _var)
{
    if (wndDebugIsOpen == true)
    {
        dbLines++;
        wndDebug.document.write("(" +  dbLines + "): " + loc + ":: " + _var + "<br />");
    }
}

function debugOutput(ex, loc)
{
    if (typeof(ex.message) != 'undefined')
    {
        fnAppendText(ex.message + '; location:' + loc);
        DebugWhisp(loc, ex.message);
    }
    else 
    {
        fnAppendText(ex + '; location:' + loc);
        DebugWhisp(loc, ex);
    }
}

//</Untility Functions>

RegExp.escape = function(text)
{
    if (!arguments.callee.sRE) {
    var specials = [
      '/', '.', '*', '+', '?', '|', '$',
      '(', ')', '[', ']', '{', '}', '\\', '^'
    ];
    arguments.callee.sRE = new RegExp(
      '(\\' + specials.join('|\\') + ')', 'gi'
    );
  }
  return text.replace(arguments.callee.sRE, '\\$1');
}

function BuildTextReplacerPattern()
{
    strcol = '';
    for (var colitem in colRepl) strcol += RegExp.escape(colitem) + '|';

    if (strcol.length > 0)
    {
        strcol = pattag + "|" + paturl + "|" + "(" + strcol.substr(0, strcol.length-1) + ")(?!\\/.+\\])";
    }
    else
    {
        strcol = pattag + "|" + paturl;
    }

    re = new RegExp(strcol, 'gi');
}
BuildTextReplacerPattern();

function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}

function fnEnterKey(e)
{
    if (e == null) e = window.event;

	if (e.keyCode == 13)
	{
		onGuestLoginDialogReturn();
	}
}

function fnCheckKey(e)
{
    if (e == null) e = window.event;

	if (e.keyCode == 13)
	{
		fnCPAppendText();
	}

	//debugOutput("ctrlkey: " + e.ctrlKey + ", keycode: " + e.keyCode + ", which" + e.which, "fnCheckKey");
	if (e.ctrlKey == true && e.shiftKey == true)
	{
	   if (isIE)
	   {
	        switch (e.keyCode)
	        {
	            case 1:
	                onBtnAction();
	                break;

	            case 13:
	                ptxSend.focus();
	                break;
	        }
	   }
	   else
	   {
	        switch (e.which)
	        {
	            case 65:
	                onBtnAction();
	                break;

	            case 13:
	                ptxSend.focus();
	                break;
	        }
	   }
	}
}

function GetFormattedNickMe()
{
    var frmtedNick;
    if (aaTagged[ouserMe.nick] == true) frmtedNick = '<span class="cpnicktaggedlocaluser">' + getUserLabel(ouserMe.nick) + '</span>';
    else if (ouserMe.away == true) frmtedNick = '<span class="cpnickawaylocaluser">' + getUserLabel(ouserMe.nick) + '</span>';
    else frmtedNick = '<span class="cpnicklocaluser">' + getUserLabel(ouserMe.nick) + '</span>';

    return frmtedNick;
}
function FormatFromByNick(sFrom)
{
    return (aaTagged[sFrom] == true)?'<span class="cpnicktaggeduser">' + getUserLabel(sFrom) + '</span>&nbsp;:&nbsp;':'<span class="cpnickuser">' + getUserLabel(sFrom) + '&nbsp;:&nbsp;</span>';
}
function FormatFromByUser(uFrom)
{
    try
    {
        var frmtedNick;
        if (aaTagged[uFrom.nick] == true) frmtedNick = '<span class="cpnicktaggeduser">' + getUserLabel(uFrom.nick) + '</span>&nbsp;:&nbsp;';
        else if (uFrom.away == true) frmtedNick = '<span class="cpnickawayuser">' + getUserLabel(uFrom.nick) + '</span>&nbsp;:&nbsp;';
        else frmtedNick = '<span class="cpnickuser">' + getUserLabel(uFrom.nick) + '&nbsp;:&nbsp;</span>';

	    return frmtedNick;
	}
	catch(ex)
    {
        debugOutput(ex, 'FormatFromByUser');
    }

}

function isHtmlTag(str)
{
    if (str.charAt(0) == "<" && str.charAt(str.length - 1) == ">") return true;
    if (str.indexOf("<") >= 0) return true;

    return false;
}

function addTagNeedClosing(etag)
{
    //current bbcode tags: stl [style]
    aTagNeedClosing.push(etag);
}

function remTagNeedClosing(etag)
{
    for (var i=(aTagNeedClosing.length - 1); i >= 0; i--)
    {
       if (etag == aTagNeedClosing[i])
       {
            switch (aTagNeedClosing[i])
            {
                case '[/STYLE]':
                    aTagNeedClosing.splice(i, 1);
                    return '</span>';
            }

       }
    }

    return null;
}

function IsTagClosings()
{
    return (aTagNeedClosing.length > 0)?true:false;
}

function closeRemaingTags()
{
    var strClosingTags = '';

    for (var i=0; i<aTagNeedClosing.length; i++)
    {
        switch(aTagNeedClosing[i])
        {
            case "[/STYLE]":
                strClosingTags += "</span>";
                break;
        }
    }

    aTagNeedClosing.splice(0, aTagNeedClosing.length);

    return strClosingTags;
}

function UnescapeSpecialChars(str)
{
    str = str.replace(/[\\]/g,'\\');
    str = str.replace(/[\b]/g,'\\b');
    str = str.replace(/[\n]/g,'\\n');
    str = str.replace(/[\r]/g,'\\r');
    str = str.replace(/[\f]/g,'\\f');

    //str = str.replace(/[&]/g,'&amp;');
    //str = str.replace(/[\]/g,'\\f');
    //str = str.replace(/[\f]/g,'\\f');

    return str;
}

function ParseTextMessage(str)
{
    return (bEmotsOff == true)?ParseTextMessage2(str, false):ParseTextMessage2(str, true);
}

function ParseTextMessage2(str, rendEmots)
{
     //ToDo: optimizations and html tag striping
	var regret = null, bbcoderet = null;
    var strtmp = '', strsubtmp = '', pos1 = 0, bSanitize = true;
    var spancount = 0;

    while (true)
    {
        regret = re.exec(str);

        if (regret != null)
        {
            if (isHtmlTag(regret[0]))
            {
                //edit begin
                if (regret[0].length > 0)
                {
                    regret[0] = sanitizeHtml(regret[0]);
                    strtmp += str.slice(pos1, regret.index) + regret[0];
                    pos1 = re.lastIndex;
                }
                //edit end
            }
            else if (regret[0].indexOf("[br]") == 0)
            {
                 strtmp += str.slice(pos1, regret.index) + "<br />";
                 pos1 = re.lastIndex;
            }
            else if (regret[0].search(reBBCODES) >= 0)
            {
                //edit begin
                if (bTextFrmtOff != true)
                {
                    strsubtmp = '';

                    while (true)
                    {   
                        bbcoderet = reBBCODES_SUB.exec(regret[0]);

                        if (bbcoderet != null)
                        {
                            if (bbcoderet[0].indexOf("ff:") == 0)
                            {
                                strsubtmp += 'font-family:' + bbcoderet[0].substr(3);
                            }
                            else if (bbcoderet[0].indexOf("bgco:") == 0)
                            {
                                strsubtmp += 'background-color:' + bbcoderet[0].substr(5);
                            }
                            else if (bbcoderet[0].indexOf("co:") == 0)
                            {
                                strsubtmp += 'color:' + bbcoderet[0].substr(3);
                            }
                            else if (bbcoderet[0].indexOf("b;") == 0)
                            {
                                strsubtmp += 'font-weight:bold;';
                            }
                            else if (bbcoderet[0].indexOf("i;") == 0)
                            {
                                strsubtmp += 'font-style:italic;';
                            }
                            else if (bbcoderet[0].indexOf("u;") == 0)
                            {
                                strsubtmp += 'text-decoration:underline;';
                            }
                            else
                            {
                                strsubtmp += 'undefined;';
                            }
                        }
                        else break;
                    }
                }
                else
                {
                    strsubtmp = 'txtfrmttingoff';
                }

                if (strsubtmp.length > 0)
                {
                    regret[0] = '<span style="' + strsubtmp + '">';
                    addTagNeedClosing('[/STYLE]');
                    strtmp += str.slice(pos1, regret.index) + regret[0];
                    pos1 = re.lastIndex;
                }
                else
                {
                    strsubtmp = remTagNeedClosing(regret[0].toUpperCase());
                    if (strsubtmp != null)
                    {
                        strtmp += str.slice(pos1, regret.index) + strsubtmp;
                        pos1 = re.lastIndex;
                    }
                }
                //edit end
            }
            else if (regret[0].search(paturl) != -1)
            {
                strtmp += str.slice(pos1, regret.index) + "<a href='"+regret[0]+"' target='_blank'>"+regret[0]+"</a>";
                pos1 = re.lastIndex;
            }
            else
            {
                //debugOutput(rendEmots ,'ParseTextMessage2');
                if (rendEmots == true)
                {
                    regret[0] = colRepl[regret[0].toLowerCase()];

                    if (regret[0] != undefined) {
                        //alert(sEmotsDir);
                        strtmp += str.slice(pos1, regret.index) + '<img src="' + sEmotsDir + regret[0] + '" border="0" />';
                        //strtmp += str.slice(pos1, regret.index) + '<img src="http://localhost:62396/fui/buzzen1/Chat_files/emots/angel.gif" border="0" />';
                        pos1 = re.lastIndex;
                    }
                }
            }
        }
        else break;
    }

    if (pos1 < str.length) strtmp += str.slice(pos1);
    if (IsTagClosings()) strtmp += closeRemaingTags();

    //alert(UnescapeSpecialChars(strtmp));
    return  UnescapeSpecialChars(strtmp);
}

function IsMyDispFormatGood()
{
    if (bTextFrmtOff == true) return false;
    if (typeof(sDspFrmt) == 'undefined') return false;
    if (sDspFrmt.length == 0) return false;

    return true;
}

function FormatSendTextMessage(str)
{
    return (IsMyDispFormatGood() == true)?'[style '+sDspFrmt+']'+str+'[/style]':str;
}

//function FormatWWSendTextMessage(str)
//{
//    alert(sDspFrmt); //window.opener.
//    return '<span style="'+sDspFrmt+'">'+str+'</span>';
//}

function RenderPrivmsg(sFrom, str)
{
	fnAppendText(FormatFromByNick(sFrom) + ParseTextMessage(str));
}

function RenderPrivmsg2(puser, str) {

    if (puser.ilevel >= IsHelpOp) {
        fnAppendText('<img unselectable="on" src="' + fnGetIco(puser) + '" border="0" class="lvuitemico" />' + FormatFromByUser(puser) + ParseTextMessage(str));
    }
    else fnAppendText('<span class="cpblankicospace"></span>' + FormatFromByUser(puser) + ParseTextMessage(str));
}

function RenderWhisp(sFrom, str, wnd)
{
    wnd.fnAppendText(FormatFromByNick(sFrom) + ParseTextMessage(str));
}

function RenderWhisp2(puser, str, wnd)
{
    if (puser.ilevel >= IsHelpOp) wnd.fnAppendText('<img unselectable="on" src="'+fnGetIco(puser)+'" border="0" class="lvuitemico" />' + FormatFromByUser(puser) + ParseTextMessage(str));
    else wnd.fnAppendText('<span class="cpblankicospace"></span>' + FormatFromByUser(puser) + ParseTextMessage(str));
}

function clearChatPane()
{
    _pcpbody.innerHTML = '';
}

function FormatTimeNums(tn)
{
    if ( tn < 10 ) return tn = "0" + tn;
    
    return tn;
}

function fnAppendText(str)
{
    bSkipCPScroll = true;
    str+= '<br />';
    
    //var tms = "";
 
    if (bTimeStampOn == true)
    {
        var dtTms = new Date();
        var tms = "[" + FormatTimeNums(dtTms.getHours()) + ":" + FormatTimeNums(dtTms.getMinutes()) + "]&nbsp;";
        str = tms + str;
    }

    if (isIE)
	{
		ChatPane.document.body.insertAdjacentHTML('beforeEnd', '<div class="linebreakindenter">' + str + '</div>');
		if (bSkipCPScrollCall == false) autoCPScroll(ChatPane.document.body);
	}
	else
	{
		var oSpan = document.createElement('div');
		oSpan.innerHTML = '<div class="linebreakindenter">' + str + '</div>';
		pChatPane.contentDocument.body.appendChild(oSpan);
		if (bSkipCPScrollCall == false) autoCPScroll(pChatPane.contentDocument.body);
	}
    
    //debugger;
	MChatPaneLines++;
	if (MChatPaneLines > (MChatPaneMaxLines - 75)) storeText('<div class="linebreakindenter">' + str + '</div>');
	fnNewMessageVisualIndicator();
}

function fnAppendText2(str)
{
    bSkipCPScroll = true;
    //str+= '<br />';

    if (isIE)
	{
		ChatPane.document.body.insertAdjacentHTML('beforeEnd', str);
		if (bSkipCPScrollCall == false) autoCPScroll(ChatPane.document.body);
	}
	else
	{
		var oSpan = document.createElement('div');
		oSpan.innerHTML = str;
		pChatPane.contentDocument.body.appendChild(oSpan);
		if (bSkipCPScrollCall == false) autoCPScroll(pChatPane.contentDocument.body);
	}
    
    //debugger;
	MChatPaneLines = 25;
	//if (MChatPaneLines > (MChatPaneMaxLines - 5)) storeText('<div class="linebreakindenter">' + str + '</div>');
	//fnNewMessageVisualIndicator();
}

function fnNewMessageVisualIndicator()
{
    if (FlashWindowEnabled) document.body.focus();
}


function storeText(str)
{
    if (bCorpText)
    {
//        if (MChatPaneLines <= MChatPaneMaxLines)
//	    {
            MChatPaneTemp += str;
       // }
        if (MChatPaneLines > MChatPaneMaxLines)
        {
            MChatPaneLines = 0;
            clearChatPane();
            fnAppendText2(MChatPaneTemp);
            MChatPaneTemp = '';
        }
    }
}

function clearChatPane()
{
    if (isIE)
        ChatPane.document.body.innerText = "";
	else
	    pChatPane.contentDocument.body.innerHTML = "";
}

function IsSendable()
{
    if ((Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && ouserMe.voice == false))
    {
        fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: Cannot send message. You need (+v) to send message in this room.</span></span>");
        return false;
    }
	else return true;
}

function fnCPAppendText()
{
	if (ptxSend.value.length > 0)
	{
	    if (IsSendable())
	    {
	        fnSend(ptxSend.value);
	        fnNewInputMessage(ptxSend.value);
	        ptxSend.value = ""; idxInputMessages = null;
	    }
	}

	ptxSend.focus();
}

function IsWWSendable(puserTo, wnd)
{
	if ((Modes[0].indexOf("w") >= 0 || Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && (ouserMe.voice == false || puserTo.voice == false) && puserTo.ilevel < IsHelpOp))
	{
		wnd.fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: Cannot send message, whispering or messaging is turned off (+m/w/x).</span></span>");
		return false;
	}
	else if (Modes[0].indexOf("W") >= 0 && (ouserMe.nick.charAt(0) == ">" || puserTo.nick.charAt(0) == ">") && (ouserMe.ilevel < IsHelpOp && puserTo.ilevel < IsHelpOp))
	{
		wnd.fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: Cannot send message, guest whispering is turned off (+W).</span></span>");
		return false;
	}
	else return true;
}

function fnWWSend(str, sNickTo, wnd)
{
    if (str.charAt(0) != '/')
    {
        //str = FormatSendTextMessage(str); //cause problems with formatting
        if (ouserMe.ilevel >= IsHelpOp) wnd.fnAppendText('<img src="'+fnGetIco(ouserMe)+'" border="0" unselectable="on" class="lvuitemico" />' + GetFormattedNickMe() + '&nbsp;:&nbsp;' + ParseTextMessage(FormatSendTextMessage(str)));
        else wnd.fnAppendText('<span class="cpblankicospace"></span>' + GetFormattedNickMe() + '&nbsp;:&nbsp;' + ParseTextMessage(FormatSendTextMessage(str)));
        flashObj.sendToServer("WHISPER " + m_sChan  + " " + sNickTo + " :" + FormatSendTextMessage(str));

        return true;
    }
    else
    {
        if (fnWhispWndCommands(str.substring(1), wnd) == true) return true;
        
        wnd.fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: That command is not available in whisper window. Please, use /? to check all the available commands</span></span>");
        
        return false;
    }

    return false;
}

function fnWhispWndCommands(sCmd, wnd)
{
    switch (sCmd.split(" ", 1)[0].toUpperCase())
	{
	    case "FIXSCROLL":
	        wnd.ScrollFix();
	        return true;
	        
	    case "?":
	        wnd.fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt2'>Commandline commands supported in whisper window: " + sanitizeHtml("FixScroll") + ".</span></span>");
	        return true;
	}
	
	return false;
}

function fnSend(str)
{
    //ToDo: disable html input
    if (str.charAt(0) != '/')
    {
        //str = FormatSendTextMessage(str); //css formatting characters had problems like Font-Family:Paprus
        //alert('<img src="'+fnGetIco(ouserMe).substr(sFUIDIR2.length)+'" border="0" />');
        if (ouserMe.ilevel >= IsHelpOp) fnAppendText('<img src="'+fnGetIco(ouserMe)+'" border="0" unselectable="on" class="lvuitemico" />' + GetFormattedNickMe() + '&nbsp;:&nbsp;' + ParseTextMessage(FormatSendTextMessage(str)));
        else fnAppendText('<span class="cpblankicospace"></span>' + GetFormattedNickMe() + '&nbsp;:&nbsp;' + ParseTextMessage(FormatSendTextMessage(str)));
        flashObj.sendToServer("PRIVMSG " + m_sChan + " :" + FormatSendTextMessage(str));

        return true;
    }
    else
    {
        return ProcessInterUserCommand(str.slice(1));
    }

    return false;
}

function fnConnect()
{
    if (IsGuestInfoSet) flashObj.sckConnect();
    else onFlashSocketLoad();
}

function fnReconnect()
{
    flashObj.PSetReconnectTimer();
}

function fnDisconnect()
{
    flashObj.sckDisconnect();
    fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Disconnected.</span></span>");
    onClearUserList();
    UpdateUserCount();
}

function ProcessInterUserCommand(sCmd)
{
	switch (sCmd.split(" ", 1)[0].toUpperCase())
	{
		case "RECONNECT":
			fnReconnect();
			break;

		case "CONNECT":
		    fnConnect();
		    break;

		case "DISCONNECT":
		    fnDisconnect();
		    break;

		case "CLEAR":
			clearChatPane();
			break;

		case "AWAY":
			ouserMe.away = false;
			ToggleAwayButton(sCmd.split(" ").slice(1).join(" "), 'cmdline');
			break;

		case "UNAWAY":
			ouserMe.away = true;
			ToggleAwayButton('', 'cmdline');
			break;

//		case "FIXCHATPANE":
//			MChatPane.redraw(true);
//			break;

		case "NICK":
			if (sCmd.split(" ")[1].length > 0) flashObj.sendToServer("NICK " + sCmd.split(" ")[1]);
			break;

		case "ME":
		    fnAction(sCmd.split(" ").slice(1).join(" "));
		    break;

		case "ENABLEFW":
		    {
		        FlashWindowEnabled = true;
		        fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " <span class='msgfrmt2'>FlashWindow enabled.</span></span></span>");
		    }
		    break;

		case "DISABLEFW":
		    {
		        FlashWindowEnabled = false;
		        fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt2'>FlashWindow disabled.</span></span>");
		    }
		    break;

		case "DEBUGPRINT":
		    {
		       flashObj.DebugPrint();
		    }
		    break;

		case "SHOWGUESTPASSSTORED":
		    {
		        fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt2'>Guest password stored: "+ flashObj.GetGuestuserPass() +"</span></span>");
		    }
		    break;
		case "SAVEGUESTPASS":
	        {
	            var strNewGuestPass = sCmd.split(" ")[1];
	            if (strNewGuestPass.length > 0)
	            {
	                flashObj.SaveGuestuserPass(strNewGuestPass);
	                strGuestPass = flashObj.GetGuestuserPass();
	                fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt2'>*Guest password stored: "+ strGuestPass +"</span></span>");
	            }
	            else
	            {
	                fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: guest password has forbidden character(s).</span></span>");
	            }
	        }
	        break;
	        
	    case "ROOMBROADCAST":
	    
	        if (ouserMe.ilevel >= IsOwner)
	        {
	            try
	            {
	                var sBCMsg = sCmd.split(" ").slice(1).join(" ");
    	            
	                flashObj.sendToServer("NOTICE " + m_sChan + " " + m_sChan + " " + sBCMsg);
	                
	                onNoticeChanBroadcast(ouserMe.nick, m_sChan, sBCMsg);
    	            
	            }
	            catch (ex)
	            {
	                debugOutput(ex, "Commandline Function");
	            }
	        }
	        else
	        {
	            fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: you must be owner or superowner to use this command.</span></span>");
	        }
	        
	        break;
	        
	    case "TOPIC":
	        if (ouserMe.ilevel >= IsHost)
	        {
	            try
	            {
	                var sCLMsg = sCmd.split(" ").slice(1).join(" ");
    	            
	                flashObj.sendToServer("PROP " + m_sChan + " TOPIC " + sCLMsg);
    	            
	            }
	            catch (ex)
	            {
	                debugOutput(ex, "Commandline Function");
	            }
	        }
	        else
	        {
	            fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: only users with level host or above can use this command.</span></span>");
	        }
	        break;
	        
	    case "WELCOME":
	        if (ouserMe.ilevel >= IsHost)
	        {
	            try
	            {
	                var sCLMsg = sCmd.split(" ").slice(1).join(" ");
    	            
	                flashObj.sendToServer("PROP " + m_sChan + " ONJOIN " + sCLMsg);
    	            
	            }
	            catch (ex)
	            {
	                debugOutput(ex, "Commandline Function");
	            }
	        }
	        else
	        {
	            fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: only users with level host or above can use this command.</span></span>");
	        }
	        break;
	        
	    case "+PROTECTIONMODE":
	        if (ouserMe.ilevel >= IsHost)
	        {
	            try
	            {
    	            
	                flashObj.sendToServer("MODE " + m_sChan + " +P");
    	            
	            }
	            catch (ex)
	            {
	                debugOutput(ex, "Commandline Function");
	            }
	        }
	        else
	        {
	            fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: only users with level host or above can use this command.</span></span>");
	        }
	        break;
	        
	    case "-PROTECTIONMODE":
	        if (ouserMe.ilevel >= IsHost)
	        {
	            try
	            {
    	            
	                flashObj.sendToServer("MODE " + m_sChan + " -P");
    	            
	            }
	            catch (ex)
	            {
	                debugOutput(ex, "Commandline Function");
	            }
	        }
	        else
	        {
	            fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: only users with level host or above can use this command.</span></span>");
	        }
	        break;

	    case "KICK":
            fnIrcKickBan(sCmd.split(" ").slice(1).join(" "), CMD_KICK);
            break;

        case "BAN15M":
            fnIrcKickBan(sCmd.split(" ").slice(1).join(" "), CMD_KICKBAN15M);
            break;

        case "BAN1H":
            fnIrcKickBan(sCmd.split(" ").slice(1).join(" "), CMD_KICKBAN1H);
            break;

        case "BAN24H":
            fnIrcKickBan(sCmd.split(" ").slice(1).join(" "), CMD_KICKBAN24H);
            break;

	    case "?":
	        fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt2'>Commandline commands supported in this client: " + sanitizeHtml("FixScroll, Reconnect, Disconnect, Clear, Away [<Away Message>], Unaway, Nick <Nickname>, DebugPrint, ShowGuestpassStored, SaveGuestpass <Guest Password>, Kick <kick message>, Ban15m <ban message>, Ban1h <ban message>, Ban24h <ban message>, TOPIC <topic message>, WELCOME <welcome message>, +/-PROTECTIONMODE") + ".</span></span>");
	        break;

	    case "DEBUGWINDOW":
	        wndDebug = window.open("fui/debug.htm", "wndDBug");
	        wndDebugIsOpen = true;
	        break;

	    case "DEBUGCLEAR":
	        wndDebug.document.body.innerHTML  = "";
	        break;
	        
	    case "INNERHTML":
	        alert(ChatPane.document.body.innerHTML);
	        break;
	        
	    case "FIXSCROLL":
	        ScrollFix();
	        break;
	        
	    case "PASS":
	    
	        var strPass = prompt("Enter password:", "");
	        //var strPass = "OWNERKEY " + m_Chan + " " + sCmd.split(" ").slice(1).join(" ");
	        try
	        {
	            if (strPass.length > 0) 
	            {
	                flashObj.sendToServer("OWNERKEY " + m_sChan + " " + strPass);
	                flashObj.sendToServer("HOSTKEY " + m_sChan + " " + strPass);
	            }
	        }
	        catch(ex)
	        {
	        }
	        break;

	    case "RAW":
	        flashObj.sendToServer(sCmd.split(" ").slice(1).join(" "));
	        break;

	    case "TEST":
	        //fnAppendText("<div class='whispreq' id='whispid123'><div id='abc123' style='color: #8b0000'><span class='cpnickuser'>TestNick</span> has sent you whispers (<a href='javascript:;' onclick='chromeTest();'>accept</a> | <a href='javascript:;' onclick='subdeclineWhisper(\"\", this);'>decline</a>).</div><div><span style='color: #8b0000'>Message:</span> " + ParseTextMessage("Test Message!") + "</div></div>");
            break;
            
		default:
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: Command \"" + sCmd.split(" ", 1)[0] +"\" is not implemented in this client.</span></span>");
			return false;
	}

	return true;
}

function updateAwayButton(away)
{
    if (away)
    {
    }
    else
    {
    }
}

var stkInputMessages = new Array();
var iMaxInputMessageStackCount = 10;
function fnNewInputMessage(str)
{
    stkInputMessages.push(str);
    if (stkInputMessages.length > iMaxInputMessageStackCount)
        stkInputMessages.splice(0, 1);
}

function fnAction(str)
{
    flashObj.sendToServer("PRIVMSG " + m_sChan + " :\1ACTION " + str + "\1");
    //fnAppendText("<span style='font-style:italic; color: #9C009C;'>" + getUserLabel(ouserMe.nick) + " " + ParseTextMessage(str) + "</span>");
    if (ouserMe.ilevel >= IsHelpOp) fnAppendText('<span style="font-style:italic; color: #9C009C;"><img unselectable="on" src="'+fnGetIco(ouserMe)+'" border="0" class="lvuitemico" />' + getUserLabel(ouserMe.nick) + " " + ParseTextMessage(str) + "</span>");
    else fnAppendText('<span style="font-style:italic; color: #9C009C;"><span class="cpblankicospace"></span>' + getUserLabel(ouserMe.nick) + " " + ParseTextMessage(str) + "</span>");
}

function ToggleAwayButton(sReason, src)
{
    //ToDo:

    if (sReason == null)
    {
        sReason = (src == 'button') ? sAwayMsg : '';
    }

	if (ouserMe.away == false)
	{
		ouserMe.away = true;
		if (sReason.length > 0) flashObj.sendToServer("AWAY " + m_sChan + " " + sReason);
		else flashObj.sendToServer("AWAY " + m_sChan + " ");
		//btnAway.gotoAndStop(2);
	}
	else
	{
		ouserMe.away = false;
		flashObj.sendToServer("AWAY " + m_sChan);
		//btnAway.gotoAndStop(1);
	}
}

function sanitizeHtml(str)
{
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/</g,'&lt;');
    str = str.replace(/>/g,'&gt;');

    return str;
}

function fnNickNameSanitize(nick)
{
    //ToDo: check if more control chars 1 to 36 needs to be sanitized
    nick = sanitizeHtml(nick);
    nick = UnescapeSpecialChars(nick);
    nick = nick.replace(/[\t]/g,'\t');

    return nick;
}

function getUserLabel(nick)
{
    return (nick.charAt(0) == ">") ? "Guest_" + fnNickNameSanitize(nick.substr(1)) : fnNickNameSanitize(nick);
}

function getUserLabel2(puser)
{
    var tnick = (puser.nick.charAt(0) == ">") ? "Guest_" + fnNickNameSanitize(puser.nick.substr(1)) : fnNickNameSanitize(puser.nick);

	if ((puser.ilevel & IsStaff) == IsStaff) tnick+= ' ' + '(Staff)';
	else if ((puser.ilevel & IsSuperOwner) == IsSuperOwner) tnick+= ' ' + '(Superowner)';
    else if ((puser.ilevel & IsOwner) == IsOwner) tnick+= ' ' + '(Owner)';
    else if ((puser.ilevel & IsHost) == IsHost) tnick+= ' ' + '(Host)';
    else if ((puser.ilevel & IsHelpOp) == IsHelpOp) tnick+= ' ' + '(Helpop)';

	return tnick;
}

function fnGetIco(puser) {

    //alert(sIcoDir);
    if (puser.tagged == true) return sIcoDir + arListIcons["ico_tagged"];
    else if (puser.away == true) return sIcoDir + arListIcons["ico_away"];
    else if ((puser.ilevel & IsStaff) == IsStaff) return sIcoDir + arListIcons["ico_staff"];
    else if ((puser.ilevel & IsSuperOwner) == IsSuperOwner) return sIcoDir + arListIcons["ico_superowner"];
    else if ((puser.ilevel & IsOwner) == IsOwner) return sIcoDir + arListIcons["ico_owner"];
    else if ((puser.ilevel & IsHost) == IsHost) return sIcoDir + arListIcons["ico_host"];
    else if ((puser.ilevel & IsHelpOp) == IsHelpOp) return sIcoDir + arListIcons["ico_helpop"];
    else if (puser.ignore == true) return sIcoDir + arListIcons["ico_ignore"];
    else if (Is_m_Mode == true || Is_x_Mode == true)
    {
        //debugOutput(puser.nick + '; ' + puser.voice, 'fnGetIco');
	    if (puser.voice == false) return sIcoDir + arListIcons["ico_spect"];
    }

    switch(puser.iprofile)
    {
	    case NoProfile:
		     return sIcoDir + arListIcons["ico_spacer"];
	    case NoGender:
		    return sIcoDir + arListIcons["ico_nogender"];
	    case NoGenderWPic:
		    return sIcoDir + arListIcons["ico_nogenderwpic"];
	    case Female:
		    return sIcoDir + arListIcons["ico_female"];
	    case FemaleWPic:
		    return sIcoDir + arListIcons["ico_femalewpic"];
	    case Male:
		    return sIcoDir + arListIcons["ico_male"];
	    case MaleWPic:
		    return sIcoDir + arListIcons["ico_malewpic"];
    }

    return sIcoDir + arListIcons["ico_spacer"];
}

function updateUserIcon(puser, pico, plb)
{
    pico.src = fnGetIco(puser);
    updateUserLabel2(puser, plb);
}

function updateUserLabel(puser, plb)
{
    if (typeof(plb.value) == 'undefined') plb.innerHTML = getUserLabel(puser.nick);
    else plb.value = getUserLabel(puser.nick);
}

function updateUserLabel2(puser, plb)
{
    //debugOutput('aaaa', 'updateUserLabel2');
    if (typeof(plb.value) == 'undefined') plb.innerHTML = getUserLabel2(puser);
    else plb.value = getUserLabel2(puser);
}

function formatUserLabel(puser, plb)
{
    if (puser.nick != ouserMe.nick)
    {
        if (olvUsers.selectedUser() != null)
        {
            if (olvUsers.selectedUser().nick == puser.nick) return;
        }

        if (puser.away == true) plb.style.color = '#696969';
        else plb.style.color = '#000099';

    }
    else
    {
        if (puser.away == true) plb.style.color = '#696969';
        else plb.style.color = '#000000';
    }
}

function getUserModeVal(smode)
{
	switch(smode)
	{
		case "v":
			return -1;
		case "h":
			return IsHelpOp;
		case "o":
			return IsHost;
		case "q":
			return IsOwner;
		case "Q":
			return IsSuperOwner;
	}

	return 0;
}

function updateUser(oUserChanges)
{
    //ToDo: optimization
	var modeval = getUserModeVal(oUserChanges.mode);
	var lvuitem = olvUsers.getItemByName(oUserChanges.param);

	if (lvuitem != null)
	{
        if (oUserChanges.op == "+")
		{
            if (modeval == -1 && lvuitem.pUser.voice != true)
			{
				tmpUser.pUser.voice = true;
				olvUsers.updateItemById(lvuitem.id, tmpUser, UPDATEUSER_ICON2);
				return lvuitem.id;
			}
			else if (((modeval & lvuitem.pUser.ilevel) != modeval) && modeval != -1)
			{
				tmpUser.pUser.ilevel = lvuitem.pUser.ilevel;
				tmpUser.pUser.host = lvuitem.pUser.host;
				//tmpUser.pUser.iprofile = lvuitem.pUser.iprofile;
				tmpUser.pUser.ilevel |= modeval;
				olvUsers.updateItemById(lvuitem.id, tmpUser, UPDATEUSER_ICON);
				return lvuitem.id;
			}
		}
		else
		{
			if (modeval == -1 && lvuitem.pUser.voice != false)
			{
			    tmpUser.pUser.voice = false;
				olvUsers.updateItemById(lvuitem.id, tmpUser, UPDATEUSER_ICON2);
				return lvuitem.id;
			}
			else if (((modeval & lvuitem.pUser.ilevel) == modeval) && modeval != -1)
			{
			    tmpUser.pUser.ilevel = lvuitem.pUser.ilevel;
				tmpUser.pUser.host = lvuitem.pUser.host;
				//tmpUser.pUser.iprofile = lvuitem.pUser.iprofile;
				tmpUser.pUser.ilevel ^= modeval;
				olvUsers.updateItemById(lvuitem.id, tmpUser, UPDATEUSER_ICON);
				return lvuitem.id;
			}
		}

		return -1;
	}

	return -1;
}

function UpdateUserCount()
{
    //alert('UpdateUserCount()');
    ptxNumberOfUser.innerHTML = (olvUsers.length() + 1) + ' users chatting';
}

function UpdateLblModes()
{
    try
    {
        ptxChanModes.innerHTML = "+" + Modes[0] + Modes[1] + Modes[2] + Modes[3] + Modes[4];
	    //if (txtModes.length == 1) ptxChanModes.innerHTML = "";
	}
	catch(ex)
    {
        debugOutput(ex, 'UpdateLblModes');
    }
}

function UpdateChatRoomText()
{
    ptxChan.innerHTML = DecodeRoomName(m_sChan);
}

function UpdateChatRoomIcon()
{
    if (Modes[0].indexOf("R") >= 0)
	{
		pchanIco.src = sIcoDir+arListIcons["ico_servicerm"];
	}
	else if (Modes[0].indexOf("r") >= 0)
	{
		pchanIco.src = sIcoDir+arListIcons["ico_regrm"];
	}
	else
	{
		pchanIco.src = sIcoDir+arListIcons["ico_spacer"];
	}
}

function DecodeRoomName(str)
{
	var sChan = str.slice(2);
	return sChan.split("\\b").join(" ");
}

function openProfileWindow(pid)
{
    var sURL = sSiteURL + "profile.aspx?pid=" + pid;
    window.open(sURL, 'wndprofile');
}

function addTag(nick)
{
    if (!aaTagged[nick])
    {
        aaTagged[nick] = true;
        flashObj.addTag(nick);
    }
}

function removeTag(nick)
{
    if (aaTagged[nick])
    {
        delete aaTagged[nick];
        flashObj.removeTag(nick);
    }
}

function BuildFmtString(pOptions)
{
    //font-family: Georgia; color: Goldenrod; font-weight: bold; font-style: normal;
    sDspFrmt = '';
    if (pOptions.font.length > 0) sDspFrmt += 'ff:' + pOptions.font + ';';
    if (pOptions.color.length > 0) sDspFrmt += 'co:' + pOptions.color + ';';
    sDspFrmt += (pOptions.bold == true) ? 'b;' : '';
    sDspFrmt += (pOptions.italic == true) ? 'i;' : '';
}

function loadOptions()
{
    var COptions = flashObj.LoadChatOptions();

    sDspFrmt = COptions.sDspFrmt;
    if (COptions.fontSize && COptions.fontSize != 'null') _pcpbody.style.fontSize = COptions.fontSize;
    bCorpText = COptions.corpText;
    sAwayMsg = (COptions.sAwayMsg == XmlNullChar) ? '' : COptions.sAwayMsg;

    if (typeof(COptions.oEventShowNotifys) != 'undefined')
    {
        var oEventShowNotifys = null;

        oEventShowNotifys = COptions.oEventShowNotifys;

        if (typeof(oEventShowNotifys.bDspArrivals) != 'undefined') bDspArrivals = oEventShowNotifys.bDspArrivals;
        if (typeof(oEventShowNotifys.bDspStatusChg) != 'undefined') bDspStatusChg = oEventShowNotifys.bDspStatusChg;
        if (typeof(oEventShowNotifys.bDspDeparts) != 'undefined') bDspDeparts = oEventShowNotifys.bDspDeparts;
    }

    if (typeof(COptions.sndArrival) != 'undefined') bSndArrival = COptions.sndArrival;
    if (typeof(COptions.sndKick) != 'undefined') bSndKick = COptions.sndKick;
    if (typeof(COptions.sndTagged) != 'undefined') bSndTagged = COptions.sndTagged;
    if (typeof(COptions.sndInvite) != 'undefined') bSndInvites = COptions.sndInvite;
    if (typeof(COptions.sndWhisp) != 'undefined') bSndWhisp = COptions.sndWhisp;

    if (typeof(COptions.bEmotsOff) == 'boolean') bEmotsOff = COptions.bEmotsOff;
    if (typeof(COptions.bTextFrmtOff) == 'boolean') bTextFrmtOff = COptions.bTextFrmtOff;
    
    if (typeof(COptions.bWhispOff) == 'boolean') bWhispOff = COptions.bWhispOff;
    if (typeof(COptions.bTimeStampOn) == 'boolean') bTimeStampOn = COptions.bTimeStampOn;

    //sound are played in flash object, so they won't load here
}

function saveOptions(pOptions)
{
    BuildFmtString(pOptions);
    _pcpbody.style.fontSize = pOptions.fontSize;
    bCorpText = pOptions.corpText;

    bDspArrivals = pOptions.showArrivals;
    bDspStatusChg = pOptions.showStatusChg;
    bDspDeparts = pOptions.showDeparts;

    bSndArrival = pOptions.sndArrival;
    bSndKick = pOptions.sndKick;
    bSndTagged  = pOptions.sndTagged;
    bSndInvites = pOptions.sndInvite;
    bSndWhisp = pOptions.sndWhisp;

    bEmotsOff = pOptions.bEmotsOff;
    bTextFrmtOff = pOptions.bTextFrmtOff;
    
    bWhispOff = pOptions.bWhispOff;
    bTimeStampOn = pOptions.bTimeStampOn;

    //
    var COptions = new Object();
    var oEventShowNotifys = new Object();

    COptions.sDspFrmt = sDspFrmt;
    COptions.fontSize = pOptions.fontSize;
    COptions.corpText = pOptions.corpText;
    COptions.sAwayMsg = (sAwayMsg == '')?XmlNullChar:sAwayMsg;

    oEventShowNotifys.bDspArrivals = bDspArrivals;
    oEventShowNotifys.bDspStatusChg = bDspStatusChg;
    oEventShowNotifys.bDspDeparts = bDspDeparts;
    COptions.oEventShowNotifys = oEventShowNotifys;

    COptions.sndArrival = pOptions.sndArrival;
    COptions.sndKick = pOptions.sndKick;
    COptions.sndTagged = pOptions.sndTagged;
    COptions.sndInvite = pOptions.sndInvite;
    COptions.sndWhisp = pOptions.sndWhisp;

    COptions.bEmotsOff = pOptions.bEmotsOff;
    COptions.bTextFrmtOff = pOptions.bTextFrmtOff;
    
    COptions.bWhispOff = pOptions.bWhispOff;
    COptions.bTimeStampOn = pOptions.bTimeStampOn;

    flashObj.SaveChatOptions(COptions);
}

function getCPBody()
{
    if (isIE) return ChatPane.document.body;
    else return pChatPane.contentDocument.body;
}

/* test code */
var dbLines = 0;
var wndDebug = null; //window.open("fui/debug.htm", "wndDBug");
var wndDebugIsOpen = false, bDebugScroll = false;

function DebugWindow(str, fnLoc)
{
    if (wndDebugIsOpen == true && bDebugScroll == true)
    {
        dbLines++;
        wndDebug.document.write("(" +  dbLines + ") Function: " + fnLoc + "<br />");
        wndDebug.document.write(sanitizeHtml(str) + "<br />");
    }
}
/* test code end */

var iLastAutoCpScrollVal = 0;
var bCPAutoScroll = true;
var bSkipCPScrollCall = false;
function autoCPScroll(cpb)
{
    if (bCPAutoScroll)
    {
        cpb.scrollTop = cpb.scrollHeight;
        iLastAutoCpScrollVal = cpb.scrollTop;
    }

/* test code begin */
    //bSkipCPScrollCall = true;
    DebugWindow("bCPAutoScroll: " + bCPAutoScroll + ", cpb.scrollTop: " + cpb.scrollTop + ", iLastAutoCpScrollVal: " + iLastAutoCpScrollVal + ", cpb.scrollHeight: " + cpb.scrollHeight, "autoCPScroll");
    //bSkipCPScrollCall = false;
/* test code end */
}

function ScrollFix()
{
    var cpb = getCPBody();
    cpb.scrollTop = cpb.scrollHeight;
    iLastAutoCpScrollVal = cpb.scrollTop;
    bCPAutoScroll = true;
}

var bScrollCallEnabled = true;
function UserScrolled()
{
    var cpb = getCPBody();
    var iScrollOffset = 20;
    
    if ((cpb.scrollTop + iScrollOffset) < iLastAutoCpScrollVal) bCPAutoScroll = false;
    else bCPAutoScroll = true;
    
    bScrollCallEnabled = true;
}

var bSkipCPScroll = false;
function OnCPScroll()
{
    var cpb = getCPBody();
    //bSkipCPScrollCall = true;
    DebugWindow("bCPAutoScroll: " + bCPAutoScroll + ", cpb.scrollTop: " + cpb.scrollTop + ", iLastAutoCpScrollVal: " + iLastAutoCpScrollVal + ", cpb.scrollHeight: " + cpb.scrollHeight, "OnCPScroll");
    //bSkipCPScrollCall = false;

    if (!bSkipCPScroll)
    {
        if (bScrollCallEnabled)
        {
            bCPAutoScroll = bScrollCallEnabled = false;
            setTimeout(UserScrolled, 1000);
        }
    }
    else bSkipCPScroll = false;
}

function fnInitialize()
{
	//MM_preloadImages( sFUIDIR + '/Chat_files/away_message_down.gif', sFUIDIR + '/Chat_files/away_message.gif', sFUIDIR + '/Chat_files/user_icon.gif', sFUIDIR + '/Chat_files/tag.gif', sFUIDIR + '/Chat_files/iggy.gif', sFUIDIR + '/Chat_files/whisper.gif', sFUIDIR + '/Chat_files/away.gif', sFUIDIR + '/Chat_files/send_down.gif', sFUIDIR + '/Chat_files/send2.gif', sFUIDIR + '/Chat_files/!_down.gif', sFUIDIR + '/Chat_files/!_2.gif');
	MM_preloadImages(sFUIDIR + '/Chat_files/away.gif', sFUIDIR + '/Chat_files/whisper.gif', sFUIDIR + '/Chat_files/iggy.gif', sFUIDIR + '/Chat_files/tag.gif', sFUIDIR + '/Chat_files/user_icon.gif', sFUIDIR + '/Chat_files/send_down.gif', sFUIDIR + '/Chat_files/send2.gif', sFUIDIR + '/Chat_files/!_down.gif', sFUIDIR + '/Chat_files/!_2.gif', sFUIDIR + '/Chat_files/set_away.gif', sFUIDIR + '/Chat_files/un_away.gif', sFUIDIR + '/Chat_files/profie_icon.gif', sFUIDIR + '/Chat_files/connect_over.gif', sFUIDIR + '/Chat_files/disconnect_over.gif', sFUIDIR + '/Chat_files/options_over.gif', sFUIDIR + '/Chat_files/smile_over.gif');
	ptxSend = document.getElementById('txSend');
	pChatPane = document.getElementById('ChatPane');
	//pChatPane.style.height = document.getElementById('tdcp').style.height;
	ptxChan = document.getElementById('txChan');
	pchanIco = document.getElementById('chanIco');
	ptxChanModes = document.getElementById('txChanModes');
	ptxNumberOfUser = document.getElementById('txNumberOfUser');
	olvUsers = new ListView(document.getElementById('lvUsers'));

	pwndGLD = document.getElementById('wndGuestLogin');
	ptxGLN = document.getElementById('txtGuestNick');
	//ppwGuest = document.getElementById('pwdGuest');
	ptxGLDErrorMessage = document.getElementById('txGLDErrorMessage');

    if (isIE) {
        flashObj = document.getElementById('ajaxfc');
        ChatPane.document.body.onscroll = OnCPScroll;
    }else {
        flashObj = document.getElementById('ajaxfcff');
        pChatPane.contentDocument.defaultView.onscroll = OnCPScroll;
    }

    plbMe = document.getElementById('lbMe');
    puicoMe = document.getElementById('uicoMe');
    //ouserMe = {nick:null, ident:null, host:null, ilevel:0, iprofile:NoProfile, away:false, awaymsg:"", voice:false};

    if (!flashsckloaded) plbMe.value = '';

    plbMe.onclick = SelectLocalUser;

    idIntIsWbrLoadedPtr = setInterval(fnIntIsWbrFlashChatObjLoaded, 96);

    //alert('tl');
    //
   //LoadDummyUsers();
}

function fnIntIsWbrFlashChatObjLoaded()
{
    if (typeof(flashObj.setLoadingCallTimer) == "function")
    {
        clearInterval(idIntIsWbrLoadedPtr);
        flashObj.setLoadingCallTimer();
    }
}

function fnMainWndUnload()
{
    plbMe.value = '';
    flashsckloaded = false;

    closeAllWhispWnds();
    if (wndChatOptions != null)
    {
        if (!wndChatOptions.closed) wndChatOptions.close();
    }
}

// <Flash Object Events>

function onFlashSocketLoad()
{
    iniContextMenu();
    iniUIObjects();

    loadOptions();

    if (iUserLoggin != USER_REG) 
    {
        if (sGuestNick == null) showGuestLoginDialog();
        else
        {
            var sGNick = sGuestNick;
            strGuestPass = flashObj.GetGuestuserPass();
            
            if (sGNick.length <= 2) sGNick += "NickLessThan2Chars";
            
            if (sGNick[0] != '>') sGNick =  '>' + sGNick;
            flashObj.SetGuestInfo(sGNick, strGuestPass);
            IsGuestInfoSet = true;
            fnConnect();
        }
    }
    else flashObj.sckConnect();

//    var sGNick = prompt("Guest Login: Enter your nick name (don't enter less than 2 characters)");

//    if (sGNick.length > 2)
//    {
//       if (sGNick[0] != '>') sGNick =  '>' + sGNick;
//       flashObj.SetGuestInfo(sGNick, 'fhejkruyg');
//       IsGuestInfoSet = true;
//       fnConnect();
//    }
}

function onClearUserList()
{
    olvUsers.removeAll();
    if (!delete aaTagged)
    {
        for (tu in aaTagged) delete tu;
    }
    aaTagged = new Array();
    UpdateUserCount();
}

function onAddUser(ouser)
{
    //debugOutput(ouser.nick + '; ' + ouser.voice, 'onAddUser');
    olvUsers.addItem(ouser);
    UpdateUserCount();
}

function onJoin(ujoined, chan)
{
    var plvi = olvUsers.addItem(ujoined);
    
    fnProcessUserIdentIngnore(plvi);
    
    if (bDspArrivals != false)
    {
        var usrname = (bShowIdentOnJoin)?getUserLabel(ujoined.nick)+"!"+ujoined.ident+"@*":getUserLabel(ujoined.nick);
        fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " " + usrname +" has joined the conversation.</span></span>");
    }
    UpdateUserCount();
    
}

function onRemoveUserByNick(sNick)
{
    //ToDo:
    //debugOutput(sNick + ' : ' + pUser.nick);
    var pUser = olvUsers.removeItemByName2(sNick);
	if (pUser != null)
	{
		if (bDspDeparts != false) fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((pUser.tagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(pUser.nick) + "</span>"):getUserLabel(pUser.nick)) +" has left the conversation.</span></span>");
		removeTag(sNick);
		EndWhispers(sNick);

		UpdateUserCount();
	}
}

function onJoinMe(oluser, sChan)
{
    ouserMe = oluser;
    m_sChan = sChan.replace(/[\b]/g, '\\b');
    //plbMe.innerHTML = getUserLabel(ouserMe.nick);
    updateUserLabel2(ouserMe, plbMe);
    uicoMe.src = fnGetIco(ouserMe);
    formatUserLabel(ouserMe, plbMe);

    flashsckloaded = true;

    UpdateChatRoomText();

    fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You have joined the conversation.</span></span></span>");

    UpdateUserCount();
}

function onNameslistMe(oluser, sChan)
{
    ouserMe = oluser;
    updateUserLabel2(ouserMe, plbMe);
    updateUserIcon(ouserMe, puicoMe, plbMe); //some redundency in these functions
    formatUserLabel(ouserMe, plbMe);
    //debugOutput("-", "onNameslistMe");
    updateLVIMenu();
    //don't update usercount, it is already being called from flash
}

function onProp(sNickFrom, sChan, sType, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    //prop returns, what if client disconnects?
	switch (sType.toUpperCase())
	{
		case "TOPIC":
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='pretopiclabel'> " + getUserLabel(sNickFrom) +" changes topic to: </span><span class='topic'>"+ ParseTextMessage(sMessage) +"</span></span>");
			break;

		case "ONJOIN":
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='preonjoinlabel'> " + getUserLabel(sNickFrom) +" changes welcome message to: </span><span class='onjoin'>"+ ParseTextMessage(sMessage) +"</span></span>");
			break;

		case "LANGUAGE2":
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " " + getUserLabel(sNickFrom) +" changes display language to: "+ sMessage +"</span></span>");
			break;
	}
}

function onNotice(sNickFrom, sChan, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    fnAppendText("<span class='msgfrmt5'><span class='titlenotice'>"+ ((aaTagged[sNickFrom] == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" (notice):</span><span class='msgnotice'>" + ParseTextMessage(sMessage) + "</span></span>");
}

function onNoticePrivate(sNickFrom, sChan, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    //ToDo:
	var plvi = olvUsers.getItemByName(sNickFrom);

	if (plvi.pUser.ignore == false || plvi.pUser.ilevel > IsSuperOwner)
	{
		if (sMessage.charAt(0) != "\2")
			fnAppendText("<span class='msgfrmt5'><span class='titlenoticepr'>"+ ((aaTagged[sNickFrom] == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" (notice):</span><span class='msgnoticepr'>" + ParseTextMessage(sMessage) + "</span></span>");
		else
		{
			var sRpl = sMessage.substr(sMessage.indexOf("\2", 1) + 1);
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ getUserLabel(sNickFrom) +"'s local time: " + ParseTextMessage(sRpl) + "</span></span>");
		}
	}
}

function onNoticeChanBroadcast(sNickFrom, sChan, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    fnAppendText("<span class='broadcasttitlecr'><img unselectable='on' src='"+ sIcoDir2 + arListIcons["ico_owner"] +"' border='0' class='lvuitemico' />&nbsp;Chat Room Broadcast:</span><br /><span class='broadcastmsg'>" + ParseTextMessage(sMessage) + "</span>");
}

function onNoticeServerBroadcast(sNickFrom, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';
    
    fnAppendText("<span class='broadcasttitlesrv'><img unselectable='on' src='"+ sIcoDir2 + arListIcons["ico_staff"] +"' border='0' class='lvuitemico' />&nbsp;Server Broadcast:</span><br /><span class='broadcastmsg'>" + ParseTextMessage(sMessage) + "</span>");
}

function onNoticeServerMessage(sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    if (!bShowServAuthMsgs)
    {
        var reSrvAuthMsgs = /^\bAUTH\b(?!.*authentication failed.*)|^There\sare|^Current\sLocal\sUsers/i;
        if (reSrvAuthMsgs.test(sMessage)) return;
    }

    fnAppendText("<span class='servnotice'>Server Notice: " + ParseTextMessage2(sMessage, false) + "</span>");
}

function onKick(sNickFrom, sChan, sNickTo, sMessage)
{
    //ToDo: check if the remove call is the correct one. whispers.

	if (sNickTo != ouserMe.nick)
	{
		if (olvUsers.removeItemByName(sNickTo) >= 0)
		{
			if (sMessage != XmlNullChar) fnAppendText("<span class='kicked'>"+ getUserLabel(sNickTo) +" has been kicked out by "+ getUserLabel(sNickFrom) +". Reason: " + ParseTextMessage(sMessage) + "</span>");
			else  fnAppendText("<span class='kicked'>"+ getUserLabel(sNickTo) +" has been kicked out by "+ getUserLabel(sNickFrom) +".</span>");
			EndWhispers(sNickTo); //ToDo: bug, if nick wrong function doesn't return
			if (bSndKick) flashObj.playKickSnd();
		}
	}
	else
	{
		if (sMessage != XmlNullChar) fnAppendText("<span class='kickedme'>You have been kicked out by "+ getUserLabel(sNickFrom) +". Reason: " + ParseTextMessage(sMessage) + "</span>");
		else fnAppendText("<span class='kicked'>You have been kicked out by "+ getUserLabel(sNickFrom) +".</span>");
		onClearUserList();
		if (bSndKick) flashObj.playKickSnd();
	}

    UpdateUserCount();
}

function onPrivmsg(sNickFrom, sChan, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    var pLVI = olvUsers.getItemByName(sNickFrom);
    var str = new String();
	if (pLVI.pUser.ignore == false || pLVI.pUser.ilevel > IsSuperOwner)
	{
	    if (sMessage.indexOf("\1") == 0)
	    {
	        //str.split(
	        var pos1 = sMessage.indexOf(" ", 1);
	        if (pos1 >= 0)
	        {
	            var sCmd = sMessage.slice(1, pos1).toUpperCase();

		        switch (sCmd)
		        {
			        case "ACTION":
				        //check ways to optimize this
				        //make action function 1 function
				        //fnAppendText("<span style='font-style:italic; color: #9C009C;'>" + getUserLabel(sNickFrom) + " " + ParseTextMessage(sMessage.substring(pos1, sMessage.length - 1)) + "</span>");
				        if (pLVI.pUser.ilevel >= IsHelpOp) fnAppendText('<span style="font-style:italic; color: #9C009C;"><img unselectable="on" src="'+fnGetIco(pLVI.pUser)+'" border="0" class="lvuitemico" />' + getUserLabel(sNickFrom) + " " + ParseTextMessage(sMessage.substring(pos1, sMessage.length - 1)) + "</span>");
                        else fnAppendText('<span style="font-style:italic; color: #9C009C;"><span class="cpblankicospace"></span>' + getUserLabel(sNickFrom) + " " + ParseTextMessage(sMessage.substring(pos1, sMessage.length - 1)) + "</span>");
				        break;

				    case "VERSION":
				        sCmd = "NOTICE " + m_sChan + " " + sNickFrom + " :\2VERSION\2" + sVersion;
				        flashObj.sendToServerQue(sCmd); //ToDo: make one qued send in js.
				        break;
		        }
		    }
		}
		else
		{
		    RenderPrivmsg2(pLVI.pUser, sMessage);
		}
	}
}

function on332(sChan, sTopic)
{
    fnAppendText("<br /><div /><span class='topicparent'><span class='pretopiclabel'>"+ txPretopiclabel +"</span><span class='topic'>"+ ParseTextMessage(sTopic) +"</span></span>");
}

function onChanPrivmsg(sChanFrom, sChan, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

	//this is welcome message (onjoin message)
	if (sChanFrom == sChan) fnAppendText("<span class='onjoinparent'><span class='onjoin'>"+ ParseTextMessage(sMessage) +"</span></span>");
}

function onPrivmsgPr(sNickFrom, sChan, sNickTo, sMessage)
{
    //ToDo:
    if (sMessage == XmlNullChar) sMessage = '';

	var plvi = olvUsers.getItemByName(sNickFrom);

	if (sMessage.charAt(0) != "\1")
	{
		if (plvi.pUser.ignore == false || plvi.pUser.ilevel > IsSuperOwner)
		{
		    //ToDo: this function is null
			RenderMessage(sNickFrom, sMessage);
			//flashObj.playTagSnd();
		}
	}
	else
	{
		var sCmd = sMessage.slice(1, sMessage.indexOf("\1", 1)).toUpperCase();

		switch (sCmd)
		{
			case "TIME":
				//check ways to optimize this
				delete dMyDate;
				dMyDate = new Date();
				sCmd = "NOTICE " + m_sChan + " " + sNickFrom + " :\2TIME\2" + flashObj.GetMyDateTime();
				flashObj.sendToServerQue(sCmd); //ToDo: make one qued send in js.
				break;
		}
	}
}

function onWhisper(sNickFrom, sChan, sNickTo, sMessage)
{
    //ToDo:
    if (sMessage == XmlNullChar) sMessage = '';

	var plvi = olvUsers.getItemByName(sNickFrom);

	if (plvi.pUser.ignore == false || plvi.pUser.ilevel > IsSuperOwner)
	{
		WhisperWindowManager(sNickFrom, sChan, sNickTo, sMessage, WHISP_IN);
	}

}

function on301(sNickFrom, sMessage)
{
    //ToDo:

    if (sMessage == XmlNullChar) sMessage = '';

	if (sNickFrom != ouserMe.nick)
	{
		var plvi = olvUsers.getItemByName(sNickFrom);

		if (plvi.pUser != undefined)
		{
		    plvi.pUser.awaymsg = sMessage;

			if (sMessage.length > 0 && (plvi.pUser.ignore == false || plvi.pUser.ilevel > IsSuperOwner))
			{
				fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((plvi.pUser.tagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" is away. Reason: " + ParseTextMessage(sMessage) + "</span></span>");
			}
			else
			{
				fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((plvi.pUser.tagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" is away.</span></span>");
			}

			//flashObj.playTagSnd();
		}
	}
	else
	{
		if (sMessage.length > 0)
		{
			ouserMe.awaymsg = sMessage;
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You are marked as being away. Away message: " + ParseTextMessage(sMessage) + "</span></span></span>");
		}
		else
		{
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4me'>" + cmdIndChar + " You are been marked as being away.</span></span>");
		}
	}
}

function on822Chan(sNickFrom, sChan, sMessage)
{
    //ToDo: add reason tool tip or something similar; optimize
    if (sMessage == XmlNullChar) sMessage = '';

	if (sNickFrom != ouserMe.nick)
	{
		var idx = olvUsers.findUser(sNickFrom);

		if (idx > -1)
		{
		    tmpUser.pUser.away = true;
		    olvUsers.updateItemById(idx, tmpUser, UPDATEUSER_FORMATING);

		    var oUser = olvUsers.getItemByName(sNickFrom).pUser;
			var bTagged = oUser.tagged;

			oUser.awaymsg = sMessage;

			if (bDspStatusChg != false)
			{
				if (sMessage.length > 0 && (oUser.ignore == false || oUser.ilevel > IsSuperOwner))
				{
					fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" went away. Reason: " + ParseTextMessage(sMessage) + "</span></span>");
				}
				else
				{
					fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" went away.</span></span>");
				}

				//flashObj.playTagSnd();
			}
		}
	}
	else
	{
		ouserMe.away = true;
		formatUserLabel(ouserMe, plbMe);
		updateUserIcon(ouserMe, puicoMe, plbMe);

		if (sMessage.length > 0)
		{
			ouserMe.awaymsg = sMessage;
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You have been marked as being away. Away message: " + ParseTextMessage(sMessage) + "</span></span></span>");
		}
		else
		{
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You have been marked as being away.</span></span></span>");
		}
	}
}

function on822Pr(sNickFrom, sMessage)
{
    //ToDo: add reason tool tip or something similar

    if (sMessage == XmlNullChar) sMessage = '';

	if (sNickFrom != ouserMe.nick)
	{
		var idx = olvUsers.findUser(sNickFrom);

		if (idx > -1)
		{
		    tmpUser.pUser.away = true;
		    olvUsers.updateItemById(idx, tmpUser, UPDATEUSER_FORMATING);

			var oUser = olvUsers.getItemByName(sNickFrom).pUser;
			var bTagged = oUser.tagged;

			oUser.awaymsg = sMessage;

			if (bDspStatusChg != false)
			{
				if (sMessage.length > 0 && (oUser.ignore == false || oUser.ilevel > IsSuperOwner))
				{
					fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):"<span class='cpnickuser'>" + getUserLabel(sNickFrom) + "</span>") +" went away. Reason: " + ParseTextMessage(sMessage) + "</span></span>");
				}
				else
				{
					fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):"<span class='cpnickuser'>" + getUserLabel(sNickFrom) + "</span>") +" went away.</span></span>");
				}

				//flashObj.playTagSnd();
			}
		}
	}
	else
	{
		ouserMe.away = true;
		formatUserLabel(ouserMe, plbMe);
		updateUserIcon(ouserMe, puicoMe, plbMe);

		if (sMessage.length > 0)
		{
			ouserMe.awaymsg = sMessage;
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> <b>You have been marked as being away. Away message: " + ParseTextMessage(sMessage) + "</span></span></span>");
		}
		else
		{
			fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> <b>You have been marked as being away.</span></span></span>");
		}
	}
}

function on821Chan(sNickFrom, sChan, sMessage)
{
    //ToDo: tagged

    if (sMessage == XmlNullChar) sMessage = '';

	if (sNickFrom != ouserMe.nick)
	{
		var idx = olvUsers.findUser(sNickFrom);

		if (idx > -1)
		{
			tmpUser.pUser.away = false;
		    olvUsers.updateItemById(idx, tmpUser, UPDATEUSER_FORMATING);
			var oUser = olvUsers.getItemById(idx).pUser;
			var bTagged = oUser.tagged;
			if (bDspStatusChg != false)
			{
			    fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):getUserLabel(sNickFrom)) +" is back.</span></span>");
			    //flashObj.playTagSnd();
			}
		}
	}
	else
	{
		ouserMe.away = false;
		formatUserLabel(ouserMe, plbMe);
		updateUserIcon(ouserMe, puicoMe, plbMe);

		fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You are no longer marked as being away.</span></span></span>");
	}
}

function on821Pr(sNickFrom, sMessage)
{
    //ToDo: tagged

    if (sMessage == XmlNullChar) sMessage = '';

	if (sNickFrom != ouserMe.nick)
	{
		var idx = olvUsers.findUser(sNickFrom);
		if (idx > -1)
		{
			tmpUser.pUser.away = false;
		    olvUsers.updateItemById(idx, tmpUser, UPDATEUSER_FORMATING);

			var oUser = olvUsers.getItemByName(sNickFrom).pUser;
			var bTagged = oUser.tagged;

			if (bDspStatusChg != false)
			{
			    fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ ((bTagged == true)?("<span class='cpnicktaggeduser'>" + getUserLabel(sNickFrom) + "</span>"):"<span class='cpnickuser'>" + getUserLabel(sNickFrom) + "</span>") +" is back.</span></span>");
			    //flashObj.playTagSnd();
			}
		}
	}
	else
	{
		ouserMe.away = false;
		formatUserLabel(ouserMe, plbMe);
		updateUserIcon(ouserMe, puicoMe, plbMe);

		fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + "<span class='msgfrmt4me'> You are no longer marked as being away.</span></span></span>");
	}
}

function onNameslist(aNames)
{
    //ToDo: check performance between js vs. flash
}

function onSetNick(sNick)
{
    ouserMe.nick = sNick;
}

function onIniLocalUser(oluser)
{
    //debugOutput("-", "onIniLocalUser");
    ouserMe = oluser;
}

function onNick(sOldNick, sNewNick)
{
    var idx = olvUsers.findUser(sOldNick);

    if (idx > -1)
    {
        tmpUser.pUser.nick = sNewNick;
        olvUsers.updateItemById(idx, tmpUser, UPDATEUSER_TEXT);

        fnAppendText("<span class='msgfrmtparent'><span class='nickchange'>" + cmdIndChar + " "+ getUserLabel(sOldNick) +" is now known as " + getUserLabel(sNewNick) + ".</span></span>");

        if (aaTagged[sOldNick])
        {
            removeTag(sOldNick);
            addTag(sNewNick);
        }

	    //ToDo: whispers, tagged event
	    WhisphersNickChange(sOldNick, sNewNick);
    }
}

function onNickMe(sNewNick)
{
    ouserMe.nick = sNewNick;
    updateUserLabel2(ouserMe, plbMe);
    fnAppendText("<span class='msgfrmtparent'><span class='nickchangeme'>" + cmdIndChar + " You are now known as " + getUserLabel(ouserMe.nick) + ".</span></span>");
}

function onChanMode(sSender, sModes, sChan)
{
    //ToDo:

	var bSignAdd = true, b_xm_ops = false;
	var bModeFound = false, aSubPos = new Array();
	var sTmpStrAdd = "", sTmpStrSubrem = "";
	var i = 0; var j = 0;

	for (i = 0; i < sModes.length; i++)
	{
		if (sModes.charAt(i) == "-")
		{
			bSignAdd = false;
			continue;
		}
		else if (sModes.charAt(i) == "+")
		{
			bSignAdd = true;
			continue;
		}

		if (bSignAdd == true)
		{
			for ( j = 0; j < Modes[0].length; j++)
			{
				if (Modes[0].charAt(j) == sModes.charAt(i))
				{
					bModeFound = true;
					break;
				}
			}

			if (bModeFound == false)
			{
				sTmpStrAdd += sModes.charAt(i);
				switch (sModes.charAt(i))
				{
					case "m":
						b_xm_ops = Is_m_Mode = true;
						break;
					case "x":
						b_xm_ops = Is_x_Mode = true;
						break;
				}
			}

			bModeFound = false;
		}
		else
		{
			for (j = 0; j < Modes[0].length; j++)
			{
				if (Modes[0].charAt(j) == sModes.charAt(i))
				{
					aSubPos.push(j);

					switch (sModes.charAt(i))
					{
						case "m":
							Is_m_Mode = false;
							b_xm_ops = true;
							break;
						case "x":
							Is_x_Mode = false;
							b_xm_ops = true;
							break;
					}

					break;
				}
			}
		}
	}

	if (aSubPos.length > 0)
	{
		i = 0;
		j = 0;

		while((i < aSubPos.length) && (j < Modes[0].length))
		{
			if (aSubPos[i] != j)
			{
				sTmpStrSubrem += Modes[0].charAt(j);
				j++;
			}
			else
			{
				i++;
				j++;
			}
		}

		if (j < Modes[0].length) sTmpStrSubrem += Modes[0].substr(j);

		Modes[0] = sTmpStrSubrem + sTmpStrAdd;
	}
	else Modes[0] = Modes[0] + sTmpStrAdd;

	if (sTmpStrSubrem.length > 0 || sTmpStrAdd.length > 0)
	{
		UpdateLblModes();
		UpdateChatRoomIcon();
		fnAppendText("<span class='msgfrmtparent'><span class='modechange'>" + cmdIndChar + " "+ getUserLabel(sSender) + " changed modes " + sModes + "</span></span>");
	}

	if (b_xm_ops == true)
	{
	    updateUserIcon(ouserMe, puicoMe, plbMe);
	    olvUsers.redrawList();
	}
}

function on324(sChan, sNModes, s_l_Mode, s_k_Mode)
{
    //ToDo:

	Modes[0] = sNModes;

	if (s_l_Mode != undefined)
	{
		Modes[1] = "l";
		Modes[3] = " " + s_l_Mode;
	}

	if (s_k_Mode != undefined)
	{
		Modes[2] = "k";
		Modes[4] = " " + s_k_Mode;
	}

	if (Modes[0].indexOf("m") >= 0) Is_m_Mode = true;
	else Is_m_Mode = false;

	if (Modes[0].indexOf("x") >= 0) Is_x_Mode = true;
	else Is_x_Mode = false;

	UpdateLblModes();
	UpdateChatRoomIcon();
	if (Is_m_Mode == true || Is_x_Mode == true) olvUsers.redrawList();
	updateUserIcon(ouserMe, puicoMe, plbMe);
}

function onChanModeWParams(sSender, modeoplist, sChan)
{
	var bModesChanged = false;
	var sModes = "", sParams = "";

	for (var i = 0; i < modeoplist.length; i++)
	{
		switch(modeoplist[i].mode)
		{
			case "l":
				if (modeoplist[i].op == "+")
				{
					Modes[1] = "l";
					Modes[3] = " " + modeoplist[i].param;
					sModes += "+l"; sParams += Modes[3];
				}
				else
				{
					Modes[1] = "";
					Modes[3] = "";
					sModes += "-l"; sParams += Modes[3];
				}
				bModesChanged = true;
				break;

			case "k":
				if (modeoplist[i].op == "+")
				{
					Modes[2] = "k";
					Modes[4] = " " + modeoplist[i].param;
					sModes += "+k"; sParams += Modes[3];
				}
				else
				{
					Modes[2] = "";
					Modes[4] = "";
					sModes += "-k"; sParams += Modes[3];
				}
				bModesChanged = true;
				break;
		}
	}

	if (bModesChanged == true)
	{
		fnAppendText("<span class='msgfrmtparent'><span class='modechange'>" + cmdIndChar + " "+ getUserLabel(sSender) + " changed modes " + sModes + sParams + "</span></span>");
		UpdateLblModes();
	}
}

function onUserMode(sSender, modeoplist, sChan)
{
	var modeval = 0, bMeModeChanged = false;
	var sTmp = "";

	for (var i = 0; i < modeoplist.length; i++)
	{
		if (modeoplist[i].param != ouserMe.nick)
		{
			if (updateUser(modeoplist[i]) >= 0)
			{
			    fnAppendText("<span class='msgfrmtparent'><span class='modechange'>" + cmdIndChar + " "+ getUserLabel(sSender) + " " + modeoplist[i].op + modeoplist[i].mode + " " + getUserLabel(modeoplist[i].param) + "</span></span>");
			}
		}
		else
		{
			modeval = getUserModeVal(modeoplist[i].mode);

			if (modeoplist[i].op == "+")
			{
				if (modeval == -1 && ouserMe.voice != true)
				{
					ouserMe.voice = true;
					bMeModeChanged = true;
					sTmp += modeoplist[i].op + modeoplist[i].mode;
				}
				else if (((modeval & ouserMe.ilevel) != modeval) && modeval != -1)
				{
					ouserMe.ilevel |= modeval;
					bMeModeChanged = true;
					sTmp += modeoplist[i].op + modeoplist[i].mode;
				}
			}
			else
			{
				if (modeval == -1 && ouserMe.voice != false)
				{
					ouserMe.voice = false;
					bMeModeChanged = true;
					sTmp += modeoplist[i].op + modeoplist[i].mode;
				}
				else if (((modeval & ouserMe.ilevel) == modeval) && modeval != -1)
				{
					ouserMe.ilevel ^= modeval;
					bMeModeChanged = true;
					sTmp += modeoplist[i].op + modeoplist[i].mode;
				}
			}
		}
	}

	if (bMeModeChanged == true)
	{
		updateUserIcon(ouserMe, puicoMe, plbMe);
		formatUserLabel(ouserMe, plbMe);
		//debugOutput("-", "onUserMode");
		updateLVIMenu();
		fnAppendText("<span class='msgfrmtparent'><span class='modechangeme'>" + cmdIndChar + " "+ getUserLabel(sSender) + " has changed your modes to " + sTmp + "</span></span>");
	}
}

function onKnock(sFrom, sChan, sMessage)
{
    if (sMessage.length > 0)
		fnAppendText("<span class='msgfrmtparent'><span class='knock'>" + cmdIndChar + " "+ getUserLabel(sFrom) + " knocked. Message: "+ ParseTextMessage(sMessage) +"</span></span>");
	else
		fnAppendText("<span class='msgfrmtparent'><span class='knock'>" + cmdIndChar + " "+ getUserLabel(sFrom) + " knocked.</span></span>");
}

//Invite Flood Protection
var LastInviteTime = 0;
var iInviteCountUnderlimit = 0;
var InviteBlockAlert = false;

function checkInviteFlood() {
    var t = new Date();

    curInviteTime = t.getTime() / 1000;

    if ((curInviteTime - LastInviteTime) > 60) {
        iInviteCountUnderlimit = 0;
        InviteBlockAlert = false;
        flashObj.InviteFlood(false);
    }
    else {
        iInviteCountUnderlimit++;
    }

    LastInviteTime = curInviteTime;

    if (iInviteCountUnderlimit > 4) return true;
}

function onInvite(sNickFrom, sNickTo, sChanFor) {

    if (checkInviteFlood() == true) {
        if (InviteBlockAlert == false) {
            fnAppendText("<span class='msgfrmtparent'><span class='invite'><i>Blocked invite floods.</i></span></span>");
            InviteBlockAlert = true;
            flashObj.InviteFlood(true);
        }
        return;
    }
    
    if (isHtmlTag(sChanFor) == false) {
        var sURI = sSiteURL + "chatui.aspx?rm=" + escape(sChanFor);
        fnAppendText("<span class='msgfrmtparent'><span class='invite'>" + cmdIndChar + " " + getUserLabel(sNickFrom) + " has invited you to chat room '<u><a href='" + sURI + "' target='_blank'>" + sChanFor.slice(2) + "</a></u>.'</span></span>");
    }
    else
        fnAppendText("<span class='msgfrmtparent'><span class='invite'><i>" + cmdIndChar + " Blocked invite from \"" + getUserLabel(sNickFrom) + "\" for security reason(s).</i></span></span>");
}

function onDataIRC(sNickBy, sType, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    if (sType == "PID")
    {
         sPID = sMessage.split(" ");
		 openProfileWindow(sPID[1]);
        return;
    }
}

function onDataIRC2(sNickFrom, sChan, sNickTo, sTag, sMessage)
{
    if (sMessage == XmlNullChar) sMessage = '';

    switch (sTag)
	{
		case "CMWHISP":
		    customWhispData(sNickFrom, sMessage);
		    break;
	}
}

function onErrorReplies(nErrorNum, sNickTo, sTarget, sMessage)
{
    //ToDo: check if all irc errors replies follow the same format. Potential for abuse, check if users can send custom messages as error replies
    if (sMessage == XmlNullChar) sMessage = '';

    switch(nErrorNum)
	{
		case "403" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: 403. Room \""+ DecodeRoomName(sTarget) +"\" does not exist.</span></span>");
			flashObj.sckDisconnect();
			break;

		case "404" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 404. "+ sMessage +"</span></span>");
			break;

		case "431" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 431. No nickname given. Please use a nickname to enter chat.</span></span>");
			break;

		case "432" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 432. The nickname you have used is erroneous. Please use another nickname.</span></span>");
			break;

		case "433" :
			if (sTarget.indexOf(">Guest") < 0) fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 433. The nickname \"" + getUserLabel(sTarget) + "\" is already in use. This client will try another nickname; you can change it later with /nick command if the command is not disabled on the server.</span></span>");
			break;

		case "441" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 441. Room \""+ DecodeRoomName(sTarget) +"\"; " + sMessage +"</span></span>");
			break;

		case "442" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 442. Room \""+ DecodeRoomName(sTarget) +"\"; " + sMessage +"</span></span>");
			break;

		case "451" :
			//fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 451. "+ sMessage +"</span></span>");
			break;

		case "461" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 461. "+ sTarget + "; " + sMessage +"</span></span>");
			break;

		case "471" :
		    fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 471. Room \""+ DecodeRoomName(sTarget) +"\" is full. You cannot join it.</span></span>");
		    //flashObj.sckDisconnect();
			break;

		case "473" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 473. Room \""+ DecodeRoomName(sTarget) +"\" is invite only. Only those who have been invited may enter this room.</span></span>");
			//flashObj.sckDisconnect();
			break;

		case "474" :
		    fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 474. You or similar mask is currently banned by a host in this \""+ DecodeRoomName(sTarget) +"\" chatroom, or banned completely from the chat service due to violations of the Code of Conduct. You may be able to reconnect at a later time.</span></span>");
		    //flashObj.sckDisconnect();
			break;

		case "475" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 475. Room \""+ DecodeRoomName(sTarget) +"\" is protected with a password. You cannot join it without correct key.</span></span>");
			//flashObj.sckDisconnect();
			break;

		case "927" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 927. Room \""+ DecodeRoomName(sTarget) +"\"; " + sMessage +"</span></span>");
			break;

		case "999" :
			fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>IRC Error: 999. "+ sMessage +"</span></span>");
			break;
	}
}

// </Flash Object Events>


//---- ListView
var loopcount = 0;
var loopcountsub = 0;

var gNewFocus;

function setFocus()
{
    gNewFocus.focus();
}

function logMax()
{
    if (loopcountsub > loopcount) loopcount = loopcountsub;
}

function ListView(pListViewParent)
{
    var plvParent = pListViewParent; var selectedItem = null;
    var alvUsers = new Array();
    var alvUsers2 = new Array();

    IntializeLV();

    //---- methods -----
    this.addItem = ptAddItem;
    this.removeItemByName = ptRemItemByName;
    this.removeItemByName2 = ptRemItemByName2;
    this.removeItemById = ptRemItemById;
    this.removeAll = fptRemoveAll;
    this.updateItemByName = null;
    this.updateItemById = ptUpdateItemById; //param:id, pUpdatedLVI; return: void;
    this.getItemByName = ptGetItemByName; //param:sNom; return: User Object Reference;
    this.getItemById = fptGetItemById;
    this.findUser = fptFindUser;
    this.redrawList = fptRedrawList;
    this.length = pfnLength;
    this.selectedUser = pfnSelectedUser;
    this.selectedLVI = pfnSelectedLVI;
    this.unselectLVI = unSelectItem;

    //---- events ----
    var bDisableOnSelectLVI = false;

    function onlvikeypress(ev, lvi)
    {
        if (ev == null) ev = window.event;
        var nlvi = null;

        try
        {
            // navflag: prev = -1, next = 1, same = 0;
            if (ev.keyCode == KEY_DOWN)
            {
                nlvi = getRelativeLVI(lvi, 1);
            }
            else if (ev.keyCode == KEY_UP)
            {
                nlvi = getRelativeLVI(lvi, -1);
            }

            //alert(nlvi);
            if (nlvi) selectItem(nlvi);
        }
        catch(ex)
        {
            debugOutput(ex, 'onlvikeypress');
        }
    }

    function onselectlvi(lvi)
    {
        if (!bDisableOnSelectLVI) selectItem(lvi);
    }

    function onDoubleClick()
    {
        OpenWhisperWindow();
    }
    //---- functions ----

    function IntializeLV()
    {
        // cleaning nodes
        while (plvParent.childNodes.length > 0)
        {
            for (var i=0; i<plvParent.childNodes.length; i++)
            {
                plvParent.removeChild(plvParent.childNodes[i]);
            }
        }
    }

    function LVIUser(id, pLVItem, pIco, pLabel, pUser)
    {
        this.id = id || -2;
        this.pLVItem = pLVItem || null;
        this.pIco = pIco || null;
        this.pLabel = pLabel || null;
        this.pUser = pUser || null;
    }

    function pfnUpdateLVIPos(lvi, pos)
    {
        lvi.id = pos;
        lvi.pLVItem.id = 'lvi' + pos;
        lvi.pIco.id = 'lvie' + pos;
        lvi.pLabel.id = 'lvit' + pos;
    }

    function getRelativeLVI(clvi, navflag)
    {
        var nlvi = null;

        switch(navflag)
        {
            case 1:
                nlvi = clvi.nextSibling;
                break;

            case -1:
                nlvi = clvi.previousSibling;
                break;
        }

        return nlvi;
    }

    function selectItem(lvi)
    {
        var pos = lvi.id.substr(3);

        unSelectItem(selectedItem);

        plbMe.className = 'lvuitemlbMe';

        selectedItem = alvUsers[pos];
        selectedItem.pLabel.style.color = '#FFFFFF';
        selectedItem.pLabel.style.backgroundColor = '#0a24a6';
        selectedItem.pLVItem.tabIndex = 0;
        gNewFocus = selectedItem.pLabel;
        setTimeout("setFocus();", 0);
        UpdateUI(selectedItem.pUser);
    }

    function unSelectItem(lvi)
    {
        if (lvi != null)
        {
            lvi.pLabel.style.color = '#0000cd';
            lvi.pLabel.style.backgroundColor = '';
            lvi.pLVItem.tabIndex = -1;
        }
    }

    function pfnSelectedUser()
    {
        return (selectedItem)?selectedItem.pUser:null;
    }

    function pfnSelectedLVI()
    {
        return (selectedItem)?selectedItem:null;
    }

    function UserCompare(u1, u2)
    {
        loopcountsub++;

        u1slev = getSimpleLevel(u1.pUser);
        u2slev = getSimpleLevel(u2.pUser);

	    if (u1slev != u2slev)
	    {
		    if (u1slev < u2slev) return 1;
		    else if (u1slev > u2slev) return -1;
		    else
		    {
			    return cnicks(u1, u2);
		    }
	    }
	    else
	    {
		    return cnicks(u1, u2);
	    }
    }

    function cnicks(u1, u2)
    {
	    if ((u1.pUser.nick.charAt(0) == ">") && (u2.pUser.nick.charAt(0) != ">")) return 1;
	    else if ((u1.pUser.nick.charAt(0) != ">") && (u2.pUser.nick.charAt(0) == ">")) return -1;
	    else
	    {
		    if (u1.pUser.nick > u2.pUser.nick) return 1;
		    else if (u1.pUser.nick < u2.pUser.nick) return -1;
		    else return 0;
	    }
    }

    function getLVIPos(lvi)
    {
        if (alvUsers.length == 0) return 0;

        var j = 0;
        var i = 0;

        for (i=0; i<alvUsers.length; i++)
        {
            j = UserCompare(alvUsers[i], lvi);
            //debugOutput(j, 'getLVIPos');
            if (j >= 0) return i;
        }
        return i;
    }

    function adjustLVItem(lvi, pos)
    {
        //ToDo: change id attrib to pos

        if (alvUsers.length == pos)
        {
            loopcountsub++;

            alvUsers.push(lvi);
            plvParent.appendChild(lvi.pLVItem);
            pfnUpdateLVIPos(lvi, pos);
        }
        else
        {
            alvUsers.splice(pos, 0, lvi);
            plvParent.insertBefore(lvi.pLVItem, alvUsers[pos+1].pLVItem);
            pfnUpdateLVIPos(lvi, pos);

            for (var i=(pos+1);i<alvUsers.length; i++)
            {
                loopcountsub++;
                pfnUpdateLVIPos(alvUsers[i], i);
            }
        }
    }

    function adjustLVItem2(lvi, p1, p2)
    {
        var istart = -1;

        if (p1 == p2 || (p1 + 1) == p2)
        {
            loopcountsub++;

            //alvUsers[p1] = lvi;
            //commented because dom nodes assignment like this causes error.
            //ToDo: check if commenting introduces some bugs
            //plvParent.childNodes[p1] = lvi.pLVItem;

        }
        else if (alvUsers.length == p2)
        {
            loopcountsub++;

            alvUsers.splice(p1, 1);
            alvUsers.push(lvi);
            pfnUpdateLVIPos(lvi, (p2 - 1));
            plvParent.removeChild(plvParent.childNodes[p1]);
            plvParent.appendChild(lvi.pLVItem);

            istart = p1;
        }
        else
        {
            alvUsers.splice(p1, 1);
            plvParent.removeChild(plvParent.childNodes[p1]);

            if (p2 < p1)
            {
                plvParent.insertBefore(lvi.pLVItem, alvUsers[p2].pLVItem);
                alvUsers.splice(p2, 0, lvi);
                istart = p2;
            }
            else
            {
                plvParent.insertBefore(lvi.pLVItem, alvUsers[p2-1].pLVItem);
                alvUsers.splice((p2 - 1), 0, lvi);
                istart = p1;
            }
        }

        if (istart != -1)
        {
            for (var i=istart; i<alvUsers.length; i++)
            {
                loopcountsub++;
                pfnUpdateLVIPos(alvUsers[i], i);
            }
        }
    }

    function getLVIChild(childid, lvi)
    {
        for (var i=0; i<lvi.childNodes.length; i++)
        {
            if (lvi.childNodes[i].id == childid) return lvi.childNodes[i];
        }
    }

    function ptAddItem(oUser)
    {
        //ToDo: optimize

        bDisableOnSelectLVI = true;

        var lvuItem = document.createElement('div');
        lvuItem.className = 'lvuitem';
        //var id = plvParent.childNodes.length;

        lvuItem.id = 'lvi' + -2;
        lvuItem.tabIndex = -1;
        lvuItem.onclick = function(){onselectlvi(this)};
        lvuItem.oncontextmenu = function(){onselectlvi(this)};
        lvuItem.ondblclick = function(){onDoubleClick(this)};

        lvuItem.onkeydown = function(event){onlvikeypress(event, this)};
        //lvuItem.onkeypress = function(){onkeypress(this)};

        lvuItem.innerHTML = '<img unselectable="on" tabindex="-1" src="'+fnGetIco(oUser)+'" border="0" class="lvuitemico" id="lvie-2" /><span unselectable="on" tabindex="-1" class="lvuitemlb" id="lvit-2" >' + getUserLabel2(oUser) + '</span>';

        var oIco = getLVIChild('lvie-2', lvuItem);
        var oLbl = getLVIChild('lvit-2', lvuItem);
        var pLVIUser = new LVIUser(-2, lvuItem, oIco, oLbl, oUser);

        formatUserLabel(oUser, oLbl);

        loopcountsub = 0;

        var pos = getLVIPos(pLVIUser);

        adjustLVItem(pLVIUser, pos);

        logMax();
        bDisableOnSelectLVI = false;

        return pLVIUser;
    }

    function removeLVItem(pos)
    {
        if (selectedItem != null)
        {
            if (alvUsers[pos].pLVItem == selectedItem.pLVItem) selectedItem = null;
        }

        lvUsers.removeChild(alvUsers[pos].pLVItem);
        alvUsers.splice(pos, 1);

        if (pos < (alvUsers.length - 1))
        {
            for (var i=pos; i<alvUsers.length; i++)
            {
                alvUsers[i].pLVItem.id = 'lvi' + i;
            }
        }
    }

    function ptRemItemByName(sNom)
    {
        //ToDo: optimize
        for (var i=0; i<alvUsers.length; i++)
        {
            if (alvUsers[i].pUser.nick == sNom)
            {
                removeLVItem(i);
                return i;
            }
        }

        return -1;
    }

    function ptRemItemByName2(sNom)
    {
        //ToDo: optimize
        for (var i=0; i<alvUsers.length; i++)
        {
            if (alvUsers[i].pUser.nick == sNom)
            {
                var pUser = alvUsers[i].pUser;
                removeLVItem(i);
                return pUser;
            }
        }

        return null;
    }

    function ptRemItemById(id)
    {
        removeLVItem(id);
    }

    function fptRemoveAll()
    {
        lvUsers.innerHTML = '';
        alvUsers.splice(0, alvUsers.length);
    }

    function ptUpdateItemById(id, pUpdatedLVI, type)
    {
       //fnAppendText(id);
       //alert(alvUsers[id].pUser.nick);
       loopcountsub = 0;

        var tmpLVIUser = alvUsers[id];
        var pos = -1;

        switch (type)
        {
            case UPDATEUSER_TEXT:
                pUpdatedLVI.pUser.ilevel = tmpLVIUser.pUser.ilevel;
                pos = getLVIPos(pUpdatedLVI);

                tmpLVIUser.pUser.nick = pUpdatedLVI.pUser.nick;
                updateUserLabel2(tmpLVIUser.pUser, tmpLVIUser.pLabel);

                adjustLVItem2(tmpLVIUser, id, pos);
                break;

            case UPDATEUSER_FORMATING:
                tmpLVIUser.pUser.away = pUpdatedLVI.pUser.away;
                formatUserLabel(tmpLVIUser.pUser, tmpLVIUser.pLabel);
                updateUserIcon(tmpLVIUser.pUser, tmpLVIUser.pIco, tmpLVIUser.pLabel);
                break;

            case UPDATEUSER_ICON:
                pUpdatedLVI.pUser.nick = tmpLVIUser.pUser.nick;
                pos = getLVIPos(pUpdatedLVI);

                tmpLVIUser.pUser.host = pUpdatedLVI.pUser.host;
                tmpLVIUser.pUser.ilevel = pUpdatedLVI.pUser.ilevel;
                //tmpLVIUser.pUser.iprofile = pUpdatedLVI.pUser.iprofile;
                updateUserIcon(tmpLVIUser.pUser, tmpLVIUser.pIco, tmpLVIUser.pLabel);
                adjustLVItem2(tmpLVIUser, id, pos);
                break;

            case UPDATEUSER_ICON2:
                tmpLVIUser.pUser.voice = pUpdatedLVI.pUser.voice;
                updateUserIcon(tmpLVIUser.pUser, tmpLVIUser.pIco, tmpLVIUser.pLabel);
                break;
        }

        logMax();
    }

    function ptGetItemByName(sNom)
    {
         //ToDo: optimize
        for (var i=0; i<alvUsers.length; i++)
        {
            if (alvUsers[i].pUser.nick == sNom) return alvUsers[i];
        }

        return null;
    }

    function fptGetItemById(pos)
    {
        if (alvUsers.length != 0 && alvUsers.length > pos) return alvUsers[pos];

        return null;
    }

    function fptFindUser(sNom)
    {
    	//ToDo: optimize
		for (var i=0; i<alvUsers.length; i++)
		{
			if (alvUsers[i].pUser.nick == sNom) return i;
		}

        return -1;
    }

    function fptRedrawList()
    {
        for (var i=0; i<alvUsers.length; i++)
        {
            formatUserLabel(alvUsers[i].pUser, alvUsers[i].pLabel);
            updateUserIcon(alvUsers[i].pUser, alvUsers[i].pIco, alvUsers[i].pLabel);
        }
    }

    function pfnLength()
    {
       return alvUsers.length;
    }
}

// <whisper windows>

var WhisperWindows = new Array();
//wndWhisperListener = new Object();
var nMaxWhispWnds = 10;
var bInComingWhispWndsMaxed = false;

var wndEIcons;
var bWndEIconsIsOpen = false;
var wndPrefs;
var bWndPrefsIsOpen = false;

var WhispTest = 'Whisper window tester';
var offsetX = 0, offsetY = 0; var bGotOffsets = false;

function testWhispWnd()
{
    return WhispTest;
}

function getWhispUser(sWhispWndNick)
{
    var idx = FindWindow(sWhispWndNick);
    if (idx >= 0)
    {
        WhisperWindows[idx].isloaded = true;
        return WhisperWindows[idx].receiver;
    }

    return null;
}

function getHash(str)
{
    //don't write full hash function, returned charcode for the nick is enough for unique id
    var strtmp = '';

    for (var i=0; i<str.length; i++)
    {
        strtmp+= str.charCodeAt(i);
    }

    return strtmp;
}

function getNewWhspId(sNick)
{
    //ToDo: optimizations, fix potential glitch
    var wid = '';
    var bmatch = false;

    if (WhisperWindows.length == 0) return getHash(sNick + '__' + Math.floor(Math.random()*1001));

    for (var i=0; i<WhisperWindows.length; i++)
    {
        wid = getHash(sNick + '__' + Math.floor(Math.random()*1001));
        bmatch = false;

        for (var j=0; j<WhisperWindows.length; j++)
        {
            if (WhisperWindows[j].whspid == wid) bmatch = true;
        }

        if (bmatch == false) return wid;
    }

    //glitch, it can return existing whspid in rare cases.
    return wid;
}

function renderWhspMsg(sNick, sMsg)
{
    var i = FindWindow(sNick);

    if (i >= 0)
    {
        WhisperWindows[i].pwnd.fnAppendText(sMsg);
    }
}

function customWhispData(nick, msg)
{
    var str = '';
    switch (msg.toUpperCase())
    {
        case "WHISPACCEPTNEEDED":
            str = "<div class='whispreq'>Waiting for <span class='cpnickuser'>" + getUserLabel(nick) + "</span> to accept your whispers. Don't send more messages until your whisper request is accepted or <span class='cpnickuser'>" + getUserLabel(nick) + "</span> may not receive your messages.</div>"
            renderWhspMsg(nick, str);
            break;

        case "WHISPACCEPTED":
            str = "<div class='whispreq'><span class='cpnickuser'>" + getUserLabel(nick) + "</span> has accepted your whisper request.</div>"
            renderWhspMsg(nick, str);
            break;

        case "WHISPDECLINED":
            str = "<div class='whispreq'><span class='cpnickuser'>" + getUserLabel(nick) + "</span> has declined your whisper request.</div>"
            renderWhspMsg(nick, str);
            break;

        case "WHISPWNDCLOSED":
            whispWndClosed(nick);
            break;
            
        case "WHISPOFF":
            str = "<div class='whispreq'><span class='cpnickuser'>" + getUserLabel(nick) + "</span> has his/her whispers turned off.</div>"
            renderWhspMsg(nick, str);
            break;
    }
}

function acceptWhisper(whspid, sender)
{
    for (var i=0; i<WhisperWindows.length; i++)
    {
        if (WhisperWindows[i].whspid == whspid)
        {
            createWhispWindow(WhisperWindows[i], null);
            //WHISPACCEPTED
            flashObj.sendToServer("DATA " + m_sChan + " " + WhisperWindows[i].receiver.nick + " CMWHISP :WHISPACCEPTED");
            sender.parentNode.parentNode.parentNode.parentNode.removeChild(sender.parentNode.parentNode.parentNode);

        }
    }
}

function declineWhisper(whspid, sender)
{
    for (var i=0; i<WhisperWindows.length; i++)
    {
        if (WhisperWindows[i].whspid == whspid)
        {
            //WHISPDECLINED
            flashObj.sendToServer("DATA " + m_sChan + " " + WhisperWindows[i].receiver.nick + " CMWHISP :WHISPDECLINED");
            RemoveWhisperWindow(i);
            sender.parentNode.parentNode.parentNode.parentNode.removeChild(sender.parentNode.parentNode.parentNode);
        }
    }
}

function whispWndClosed(nick)
{
    var i = FindWindow(nick);

    if (i >= 0)
    {
        var str = '';

        if (WhisperWindows[i].isloaded == true)
        {
            str = "<div class='whispreq'><span class='cpnickuser'>" + getUserLabel(nick) + "</span> has closed whisper window.</div>";
            renderWhspMsg(nick, str);
        }
        else
        {
            var pnode = getByIdFromCP(WhisperWindows[i].whspid);
	        if (pnode != null)
	        {
	            str = "<span class='cpnickuser'>" + getUserLabel(nick) + "</span> has closed whisper window.";
	            pnode.innerHTML = str;
	            RemoveWhisperWindow(i);
	        }
	    }
    }
}

function preCreateWhispWindow(puserTo, type)
{
    if (WhisperWindows.length < nMaxWhispWnds)
    {
        var i = FindWindow(puserTo.nick);
        
        DebugWhisp('preCreateWhispWindow_WndIndex', i);

        if (i < 0)
        {
            var wndWhisp = new Object();
            wndWhisp.receiver = puserTo;
            wndWhisp.isloaded = false;
            wndWhisp.type = type;
            wndWhisp.whspid = getNewWhspId(puserTo.nick);
            WhisperWindows.push(wndWhisp);
            
            DebugWhisp('NewWhisperObjectCreated', '');

            if (type == WHISP_OUT)
            {
                createWhispWindow(wndWhisp, type);
            }

            return wndWhisp;
        }
        else
        {
            DebugWhisp('WhisperObjectAlreadyExists', '');
            
            createWhispWindow(WhisperWindows[i], type);
            flashObj.sendToServer("DATA " + m_sChan + " " + WhisperWindows[i].receiver.nick + " CMWHISP :WHISPACCEPTED");
            
            DebugWhisp('Removing Whisper alert from chatpane', '');
            
            var pnode = getByIdFromCP(WhisperWindows[i].whspid);
	        
	        if (pnode != null)
	        {
	            remWhispRequest(pnode);
	        }
        }
    }
    else
	{
		fnAppendText("<font face='Tahoma' color='#FF3300'>[Alert: Instances of whisper windows have exceeded max limit. If you want to open new whispers conversation in new window, then close some whisper windows.</font>");
		bInComingWhispWndsMaxed = true;
	}
}

function createWhispWindow(wndWhisp, type)
{
    try
    {
            //debugger;
            
            if (WhispWndIsLoaded(wndWhisp) == 1) return wndWhisp;
            
            var bWndWhispCreateError = false;
            var sWWDir = sFUIDIR2;
            
            DebugWhisp('CreatingWhisperWindow', '');

            if (wndWhisp.type==WHISP_IN && isIE) sWWDir = sURIFUIDIR2;

            DebugWhisp('Getting position for new whisper window', '');
            wndpos = getWhispWindowPos();

            DebugWhisp('CreatingWhisperWindowInstance', '');
            
            try
            {
                wndWhisp.pwnd = window.open(sWWDir + 'wndWhisper.htm', wndWhisp.whspid, 'left='+wndpos.x+',top='+wndpos.y+',width=575,height=312,toolbar=0,resizable=0,directories=0,status=yes,menubar=0,scrollbars=0,titlebar=0,location=0');
                
                if (wndWhisp.pwnd) DebugWhisp('WhisperWindowInstanceCreationSuccessful', '');
                else bWndWhispCreateError = true;
                
            }
            catch (ex)
            {
                //debugOutput(ex, 'createWhispWindow');
                bWndWhispCreateError = true;
            }
            
            if (bWndWhispCreateError == true)
            {
                DebugWhisp('WhisperWindowInstanceCreationFailed', '');
                fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: Whisper window creation failed; popup-blocker may have blocked creation of whisper window instance.</span></span>");
                return null;
            }
            
            //alert("A:" + wndWhisp.pwnd.closed);
            
            DebugWhisp('Setting WhisperWindow Variables', '');
            
            if (!wndWhisp.pwnd.opener) wndWhisp.pwnd.opener = self;

            wndWhisp.pwnd.sWNick = wndWhisp.receiver.nick;

            if (wndWhisp.type==WHISP_IN)
            {
                wndWhisp.pwnd.tmpmessages = wndWhisp.inmsgs;
            }

            wndWhisp.isloaded = true;
            
            DebugWhisp('Setting WhisperWindow Postion offsets', '');

            if (isIE)
            {
                if (bGotOffsets == false)
                {
                    offsetX = wndWhisp.pwnd.screenLeft - wndpos.x;
                    offsetY = wndWhisp.pwnd.screenTop - wndpos.y;
                }
            }

            wndWhisp.pwnd.isloaded = false;
            /*
            if (wndWhisp.pwnd.setWhispWndVars)
            {
                debugOutput('ww7a', 'createWhispWindow');
                debugger;
                wndWhisp.pwnd.setWhispWndVars(wndWhisp.receiver);
                wndWhisp.pwnd.isloaded = true;
                debugOutput('ww7b', 'createWhispWindow');
            }
            else
            {
                debugOutput('ww7c', 'createWhispWindow');
                wndWhisp.pwnd.isloaded = false;
                debugOutput('ww7d', 'createWhispWindow');
            }
            */
            return wndWhisp;
    }
    catch (ex)
    {
        debugOutput(ex, 'createWhispWindow');
    }

}

function OpenWhisperWindow()
{
    if (pBtnWhisp.disable != true)
    {
        preCreateWhispWindow(olvUsers.selectedUser(), WHISP_OUT);
    }
}

function WhisperWindowManager(sNickFrom, sChan, sNickTo, sMessage, type)
{
	var ret = FindWindow(sNickFrom);
	
	if (ret == -1 && WhisperWindows.length <= nMaxWhispWnds)
	{
		if (type == WHISP_OUT)
		{
		    //create new window
		    var wndWhisp = preCreateWhispWindow(olvUsers.getItemByName(sNickFrom).pUser, type);
		
		    if (wndWhisp.pwnd.isloaded == false) wndWhisp.pwnd.tmpmessages += FormatFromByNick(sNickFrom) + ParseTextMessage(sMessage);
		    else RenderWhisp2(olvUsers.getItemByName(sNickFrom).pUser, sMessage, wndWhisp.pwnd);
		}
		else {

		    var puser = olvUsers.getItemByName(sNickFrom).pUser;

		    if (bWhispOff == false || puser.ilevel >= IsStaff)
            {
                //create new window
                var wndWhisp = preCreateWhispWindow(puser, type);

                if (!isWK) str123 = "<div class='whispreq' id='" + wndWhisp.whspid + "'><div id='abc123' style='color: #8b0000'><span class='cpnickuser'>" + getUserLabel(sNickFrom) + "</span> has sent you whispers (<a href='javascript:;' onclick='subacceptWhisper(\"" + wndWhisp.whspid + "\", this);'>accept</a> | <a href='javascript:;' onclick='subdeclineWhisper(\"" + wndWhisp.whspid + "\", this);'>decline</a>).</div><div><span style='color: #8b0000'>Message:</span> " + ParseTextMessage(sMessage) + "</div></div>";
                else str123 = "<div class='whispreq' id='" + wndWhisp.whspid + "'><div id='abc123' style='color: #8b0000'><span class='cpnickuser'>" + getUserLabel(sNickFrom) + "</span> has sent you whispers (<a href='javascript:;' onclick='acceptWhisper(\"" + wndWhisp.whspid + "\", this);'>accept</a> | <a href='javascript:;' onclick='declineWhisper(\"" + wndWhisp.whspid + "\", this);'>decline</a>).</div><div><span style='color: #8b0000'>Message:</span> " + ParseTextMessage(sMessage) + "</div></div>";
                fnAppendText(str123);
                wndWhisp.inmsgs = sMessage;
                wndWhisp.inmsgscount = 0;
                wndWhisp.inmsgscount++;
                //ToDo: sChan function var was causing problem with channels that have \b, check for other javascript escape characters.
                flashObj.sendToServer("DATA " + m_sChan + " " + sNickFrom + " CMWHISP :WHISPACCEPTNEEDED");
            }
            else
            {
                flashObj.sendToServer("DATA " + m_sChan + " " + sNickFrom + " CMWHISP :WHISPOFF");
            }
        }

		if (bSndWhisp != false && bWhispOff == false ) flashObj.playWhispSnd();
	}
	else
	{
		if (ret >= 0)
		{
			//render message to the window
			if (WhisperWindows[ret].isloaded == true)
			{
			    if (WhisperWindows[ret].pwnd.isloaded == false)
			    {
			        var puser = olvUsers.getItemByName(sNickFrom).pUser;
			        if (puser.ilevel >= IsHelpOp) WhisperWindows[ret].pwnd.tmpmessages += '<img unselectable="on" src="'+fnGetIco(puser)+'" border="0" class="lvuitemico" />' + FormatFromByNick(sNickFrom) + ParseTextMessage(sMessage);
			        else WhisperWindows[ret].pwnd.tmpmessages += '<span class="cpblankicospace"></span>' + FormatFromByUser(puser) + ParseTextMessage(str);
			    }
			    else RenderWhisp2(WhisperWindows[ret].pwnd.whispUser, sMessage, WhisperWindows[ret].pwnd);
			}
			else
			{
			    //render message to the main window
			    fnAppendText("<font face='Tahoma' color='#660099'><b>"+ getUserLabel(sNickFrom) +" Whispered:</b></font>" + ParseTextMessage(sMessage));
			}
		}
		else
		{
			//window instances have reached max limit render the message in main chat pane
			if (bInComingWhispWndsMaxed == false)
			{
				fnAppendText("<font face='Tahoma' color='#FF3300'>[Alert: Instances of whisper windows have exceeded max limit. If you want to open new whispers conversation in new window, then close some whisper windows.</font>");
				bInComingWhispWndsMaxed = true;
				if (bSndWhisp != false) flashObj.playWhispSnd();
			}
			fnAppendText("<font face='Tahoma' color='#660099'><b>"+ getUserLabel(sNickFrom) +" Whispered:</b></font>" + ParseTextMessage(sMessage));
		}
	}
}

function getWhispWindowPos()
{
    var wnd = new Object();
    var rval = -1;
    wnd.x = 20;
    wnd.y = 20;

	for (var i = 0; i<WhisperWindows.length; i++)
	{
	    //console.debug(WhisperWindows);
	    rval = WhispWndIsLoaded(WhisperWindows[i]);
	    
	    if (rval == 1)
	    {
	        if (isIE)
	        {
		        if ((wnd.x == (WhisperWindows[i].pwnd.screenLeft - offsetX)) && (wnd.y == (WhisperWindows[i].pwnd.screenTop - offsetY)))
		        {
			        wnd.x+= 10;
			        wnd.y+= 15;
		        }
		    }
		    else
		    {
		        if ((wnd.x == WhisperWindows[i].pwnd.screenX) && (wnd.y == WhisperWindows[i].pwnd.screenY))
		        {
			        wnd.x+= 10;
			        wnd.y+= 15;
		        }
		    }
		}
		else if (rval == 0)
		{
		    RemoveWhisperWindow(i);
		}
	}

	return wnd;
}


function WhispWndIsLoaded(wndWhisp)
{
    try
    {
        if (typeof(wndWhisp.pwnd) != 'undefined' && wndWhisp.pwnd != null && wndWhisp.isloaded == true) 
        {
            //var wintest = wndWhisp.pwnd.screenTop;
            //alert("B:" + wndWhisp.pwnd.closed);
            
            if (wndWhisp.pwnd.closed == true) return 0;
            
            return 1;
        }
    }
    catch (ex)
    {
        debugOutput(ex, 'WhispWndIsLoaded');
    }
    
    return -1;
}

function WhisphersNickChange(sOldNick, sNewNick)
{
    //debugger;
	var ret = FindWindow(sNewNick); //user object it updated b4 this function is called

	if (ret >= 0)
	{
		WhisperWindows[ret].receiver.nick = sNewNick;

		if (WhisperWindows[ret].isloaded == true)
		{
		    var str = "<span class='msgfrmtparent'><font face='Tahoma' color='#0099FF'>" + cmdIndChar + " "+ getUserLabel(sOldNick) +" is now known as " + getUserLabel(sNewNick) + ".</font></span>";

		    if (WhisperWindows[ret].pwnd.isloaded == true)
		    {
		        WhisperWindows[ret].pwnd.setWhispWndVars(WhisperWindows[ret].receiver);
		        WhisperWindows[ret].pwnd.fnAppendText(str);
		    }
		    else
		        WhisperWindows[ret].pwnd.tmpmessages += str;
		}
		else
		{
		    //ToDo: check if something here is needed.
		}
	}
}

function EndWhispers(sNick)
{
	var ret = FindWindow(sNick);

	if (ret >= 0)
	{
		var str = "<font face='Tahoma' color='#FF3300'>" + getUserLabel(sNick) + " has left the conversation.</font>";

		if (WhisperWindows[ret].isloaded == true)
		{
		    WhisperWindows[ret].userLeft = true;
		    if (WhisperWindows[ret].pwnd.isloaded == false) WhisperWindows[ret].pwnd.tmpmessages += str;
		    else WhisperWindows[ret].pwnd.fnAppendText(str);   //RenderWhisp(sNick, str, WhisperWindows[ret].pwnd);
		}
		else
		{
		    RemoveWhisperWindow(ret);
		}
	}
}

function FindWindow(sNick)
{
	//don't use hash tables for this one. For short list, simple search is faster than hash table
	for (var i = 0; i<WhisperWindows.length; i++)
	{
		if (WhisperWindows[i].receiver.nick == sNick) return i;
	}

	return -1;
}

function closeWhispWnd(WhispWndNick)
{
    var idx = FindWindow(WhispWndNick);
    if (idx >= 0)
    {
        var userLeft = false;
        
        try
        {
            if ( typeof(WhisperWindows[i].userLeft) != "undefined" )
            {
                if (WhisperWindows[i].userLeft == true) userLeft = true;
            }
        }
        catch (ex)
        {
        }
        
        RemoveWhisperWindow(idx);
        //WHISPWNDCLOSED
        if (userLeft != true) flashObj.sendToServer("DATA " + m_sChan + " " + WhispWndNick + " CMWHISP :WHISPWNDCLOSED");
    }
}

function closeAllWhispWnds()
{
    for (var i = 0; i<WhisperWindows.length; i++) RemoveWhisperWindow(i);
}

function remWhispRequest(pnode)
{
    pnode.parentNode.removeChild(pnode);
}

function RemoveWhisperWindow(idx)
{
	if (idx >= 0 && WhisperWindows[idx])
	{
	    if (WhisperWindows[idx].isloaded == true)
	    {
	        WhisperWindows[idx].pwnd.close();
	        delete WhisperWindows[idx].pwnd;
	    }
	    else
	    {
//	        var pnode = getByIdFromCP(WhisperWindows[idx].whspid);
//	        if (pnode != null) remWhispRequest(pnode);
	    }
		WhisperWindows.splice(idx, 1);
	}
}

//</whisper windows>

function getByIdFromCP(id)
{
    var node = (isIE) ? ChatPane.document.getElementById(id) : pChatPane.contentDocument.getElementById(id);
    return node;
}

//---- <menu>
var _pmnucp = null, _pmnuhost = null, _pmnuhelpop = null, _pmnuuser = null;
var _clvicmnu = null;
var _pcpbody = null; var _pwndChat = null;
var _mnuitemselected = false, prevmnuselected = null, _mnukeynavetimeout = true;

var _pMnuCopy = null;
var _pmiVPU = null, _pmiWU = null, _pmiIU = null, _pmiTUU = null, _pmiLTU = null, _pmiAMU = null;
var _pmiVPHO = null, _pmiWHO = null, _pmiIHO = null, _pmiTUHO = null, _pmiLTHO = null, _pmiAMHO = null, _pmiVHO = null, _pmiPHO = null, _pmiKHO = null;
//at the moment I'm adding owner mode in host menu, I may change this later and give owner and superowner their own menu.
var _pmiVPH = null, _pmiWH = null, _pmiIH = null, _pmiTUH = null, _pmiLTH = null, _pmiAMH = null, _pmiKH = null, _pmiB15mH = null, _pmiB1hH = null, _pmiB24hH = null, _pmiVH = null, _pmiPH = null, _pmiHOH = null, _pmiHH = null, _pmiOH = null;



//

var seltx = null;

function copyCP()
{
    if (isIE) {
        //flashObj.copyToClipboard(_pcpbody.document.selection.createRange().text);
        clipboardData.setData("Text", _pcpbody.document.selection.createRange().text);
    }
    else if (isFF) {
        alert("Firefox doesn't allow copy to clipboard through javascript. To know alternative way, please see Help Desk.");
    }
    else if (isWK) {
        pChatPane.contentDocument.execCommand("copy");
    }

    closeAllMenus();
}

function selectAllCP()
{
    if (isIE) {
        seltx = _pcpbody.createTextRange();
        seltx.select();
    }
    else {
        pChatPane.contentDocument.defaultView.getSelection().selectAllChildren(_pcpbody);
        pChatPane.contentDocument.defaultView.focus();
    }

    closeAllMenus();
}

function clearCP()
{
    clearChatPane();
    closeAllMenus();
}

function mifViewProfile()
{
    fnViewProfile();
	closeAllMenus();
}

function mifWhisper()
{
    setTimeout('closeAllMenus()', 7);
    OpenWhisperWindow();
}

function mifIgnore()
{
    fnIgnore();
	closeAllMenus();
}

function mifTaguser()
{
    fnTag();
	closeAllMenus();
}

function mifLocaltime()
{
    if (cmnuSelMe == false)
    {
        var cmdGetTime = "PRIVMSG " + m_sChan + " " + olvUsers.selectedUser().nick + " :\1TIME\1";
	    flashObj.sendToServer(cmdGetTime);
	    //debugOutput(cmdGetTime, 'mifLocaltime');
	}
	else
	{
	    fnAppendText("<span class='msgfrmtparent'><span class='msgfrmt4'>" + cmdIndChar + " "+ getUserLabel(ouserMe.nick) +"'s local time: " + ParseTextMessage(flashObj.GetMyDateTime()) + "</span></span>");
	}

	closeAllMenus();
}

function mifAwayMessage()
{
    var cmdGetAwayMsg = "AWAYMSG " + m_sChan + " " + olvUsers.selectedUser().nick;
	flashObj.sendToServer(cmdGetAwayMsg);
	closeAllMenus();
}

function mifVoice()
{
    var sIRCCMD = "";

    if (cmnuSelMe == false)
    {
	    if (olvUsers.selectedUser().voice == true) sIRCCMD = "MODE " + m_sChan + " -v " + olvUsers.selectedUser().nick;
	    else sIRCCMD = "MODE " + m_sChan + " +v " + olvUsers.selectedUser().nick;
	}
	else
	{
	    if (ouserMe.voice == true) sIRCCMD = "MODE " + m_sChan + " -v " + ouserMe.nick;
	    else sIRCCMD = "MODE " + m_sChan + " +v " + ouserMe.nick;
	}

	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifParti()
{
    var sIRCCMD = "";

    if (cmnuSelMe == false)
    {
	    sIRCCMD = "MODE " + m_sChan + " -qoh " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick;
	}
	else
	{
	    sIRCCMD = "MODE " + m_sChan + " -qoh " + ouserMe.nick + " " + ouserMe.nick + " " + ouserMe.nick;
	}

	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifHelpOp()
{
    var sIRCCMD = "";

    if (cmnuSelMe == false)
    {
	    if ((olvUsers.selectedUser().ilevel & IsHelpOp) == IsHelpOp) sIRCCMD = "MODE " + m_sChan + " -h " + olvUsers.selectedUser().nick;
	    else sIRCCMD = "MODE " + m_sChan + " +h-qo " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick;
	}
	else
	{
	    if ((ouserMe.ilevel & IsHelpOp) == IsHelpOp) sIRCCMD = "MODE " + m_sChan + " -h " + ouserMe.nick;
	    else sIRCCMD = "MODE " + m_sChan + " +h-qo " + ouserMe.nick + " " + ouserMe.nick + " " + ouserMe.nick;
	}

	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifHost()
{
    var sIRCCMD = "";

    if (cmnuSelMe == false)
    {
	    if ((olvUsers.selectedUser().ilevel & IsHost) == IsHost) sIRCCMD = "MODE " + m_sChan + " -oh " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick;
	    else sIRCCMD = "MODE " + m_sChan + " +o-q " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick;
    }
    else
    {
        if ((ouserMe.ilevel & IsHost) == IsHost) sIRCCMD = "MODE " + m_sChan + " -oh " + ouserMe.nick + " " + ouserMe.nick;
	    else sIRCCMD = "MODE " + m_sChan + " +o-q " + ouserMe.nick + " " + ouserMe.nick;
    }

	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifOwner()
{
    var sIRCCMD = "";

    if (cmnuSelMe == false)
    {
	    if ((olvUsers.selectedUser().ilevel & IsOwner) == IsOwner) sIRCCMD = "MODE " + m_sChan + " -qoh " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick + " " + olvUsers.selectedUser().nick;
	    else sIRCCMD = "MODE " + m_sChan + " +q " + olvUsers.selectedUser().nick;
    }
    else
    {
        if ((ouserMe.ilevel & IsOwner) == IsOwner) sIRCCMD = "MODE " + m_sChan + " -qoh " + ouserMe.nick + " " + ouserMe.nick + " " + ouserMe.nick;
	    else sIRCCMD = "MODE " + m_sChan + " +q " + ouserMe.nick;
    }

	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifKick()
{
    var sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick;
	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function fnIrcKickBan(sMsg, type)
{
    if (olvUsers.selectedUser() != null)
    {
        var sIRCCMD = null;

        if (sMsg.length > 0 )
        {
            sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick + " " + sMsg;
        }
        else
        {
            sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick;
        }

        switch(type)
        {
            case CMD_KICK:
                break;

            case CMD_KICKBAN15M:
                sIRCCMD += " (ban 15 mins.).\r\n";
                sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 15 :";
                break;

            case  CMD_KICKBAN1H:
                sIRCCMD += " (ban 1 hr.).\r\n";
                sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 60 :";
                break;

            case CMD_KICKBAN24H:
                sIRCCMD += " (ban 24 hrs.).\r\n";
                sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 1440 :";
                break;
        }

	    flashObj.sendToServer(sIRCCMD);
	}
	else
	{
	    fnAppendText("<span class='msgfrmtparent'><span class='errortype1'>Error: no user selected.</span></span>");
	}
}

function mifBan15m()
{
    var sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick + "\r\n";
	sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 15 :";
	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifBan1h()
{
    var sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick + "\r\n";
	sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 60 :";
	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

function mifBan24h()
{
    var sIRCCMD = "KICK " + m_sChan + " " + olvUsers.selectedUser().nick + "\r\n";
	sIRCCMD += "ACCESS " + m_sChan + " ADD DENY *!" + olvUsers.selectedUser().ident + "@* 1440 :";
	flashObj.sendToServer(sIRCCMD);
	closeAllMenus();
}

//

function getById(id)
{
    return document.getElementById(id);
}

function menuMouseIn(mnu)
{
    _mnuitemselected = true;
}

function menuMouseOut(mnu)
{
    _mnuitemselected = false;
}

function menuItemMouseIn(mnuitem)
{
    if (!_mnukeynavetimeout) return;
    selectMnuItem(mnuitem);
}

function menuItemMouseOut(mnuitem)
{
    if (!_mnukeynavetimeout) return;
    unselectMnuItem(mnuitem);
    //if (prevmnuselected != null) unselectMnuItem(prevmnuselected);
}

function selectMnuItem(mnuitem)
{
    if (prevmnuselected != mnuitem)
    {
        if (prevmnuselected != null) unselectMnuItem(prevmnuselected);

        if (!mnuitem.disabled)
        {
            mnuitem.style.color = '#FFFFFF';
            mnuitem.style.backgroundColor = '#0a24a6';
            //mnuitem.tabIndex = 0;
            gNewFocus = mnuitem;
            prevmnuselected = mnuitem;
            setTimeout("setFocus();", 0);
        }
    }
}

function unselectMnuItem(mnuitem)
{
    _mnuitemselected = false;

    if (!mnuitem.disabled)
    {
        mnuitem.style.color = '#000000';
        mnuitem.style.backgroundColor = 'menu';
        //mnuitem.tabIndex = -1;
    }
}

function fnKeyNavTimeout()
{
    _mnukeynavetimeout = true;
}

function mnuOnKeyPress(ev, mnui)
{
    if (ev == null) ev = window.event;
    var nmnu = null;

    try
    {
        // navflag: prev = -1, next = 1, same = 0;
        if (ev.keyCode == KEY_DOWN)
        {
            //debugOutput('keydown');
            nmnu = getRelativeMenuItem(mnui, 1);
        }
        else if (ev.keyCode == KEY_UP)
        {
            //debugOutput('keyup');
            nmnu = getRelativeMenuItem(mnui, -1);
        }
        else if (ev.keyCode == KEY_BACKSPACE)
        {
            ev.returnValue = false;
        }

        if (nmnu)
        {
            setTimeout("fnKeyNavTimeout();", 10);
            selectMnuItem(nmnu);
        }
    }
    catch(ex)
    {
        debugOutput(ex, 'mnuOnKeyPress');
    }

    //ev.keyCode = 0;
    ev.cancelBubble = true;
    return false;
}

function getRelativeMenuItem(mnuitem, navflag)
{
    var tmnuitem = null;

    switch (navflag)
    {
        case -1:
            if (mnuitem.className == 'menuitem')
            {
                   if (mnuitem.previousSibling) tmnuitem = mnuitem.previousSibling;

                   while (tmnuitem)
                   {
                        if (!tmnuitem.disabled && tmnuitem.className == 'menuitem')
                        {
                            return tmnuitem;
                        }
                        tmnuitem = tmnuitem.previousSibling;
                   }

                   return getLastMenuItem(mnuitem.parentNode);
            }
            else return getLastMenuItem(mnuitem);
        case 1:
            if (mnuitem.className == 'menuitem')
            {
                if (mnuitem.nextSibling) tmnuitem = mnuitem.nextSibling;

                while (tmnuitem)
                {
                    if (!tmnuitem.disabled && tmnuitem.className == 'menuitem')
                    {
                        return tmnuitem;
                    }

                    tmnuitem = tmnuitem.nextSibling;
                }

                return getFirstMenuItem(mnuitem.parentNode);
            }
            else return getFirstMenuItem(mnuitem);
    }

    return null;
}

function getFirstMenuItem(parentmnu)
{
    for (var i=0; i<parentmnu.childNodes.length; i++)
    {
        if (!parentmnu.childNodes[i].disabled && parentmnu.childNodes[i].className == 'menuitem') return parentmnu.childNodes[i];
    }

    return null;
}

function getLastMenuItem(parentmnu)
{
    for (var i=(parentmnu.childNodes.length - 1); i>=0; i--)
    {
        if (!parentmnu.childNodes[i].disabled && parentmnu.childNodes[i].className == 'menuitem') return parentmnu.childNodes[i];
    }

    return null;
}

function IsCPTextSelected()
{
    if (isIE) {
        if (_pcpbody.document.selection.type.toLowerCase() == 'none') return false;
        else return true;
    } //pChatPane.contentDocument
    else if (isFF) {
        if (pChatPane.contentDocument.getSelection().length == 0) return false;
        else return true;
    }
    else if (isWK) {
        if (pChatPane.contentDocument.getSelection().toString().length == 0) return false;
        else return true;
    }

    return false;
}

function getEventObject()
{
    //only for IE. IE doesn't pass event.

    if (window.event != null) return window.event;
    else
    {
        if (isIE) return window.frames['ChatPane'].window.event;
    }
}

function onMouseDown(event)
{
    if (_mnuitemselected == true) return;
    closeAllMenus();

}

function showMenu(pmnu, event)
{
    var _cmnuSelMe = cmnuSelMe;
    closeAllMenus();
    //debugOutput("_cmnuSelMe: " + _cmnuSelMe, "showMenu");
    if (_cmnuSelMe) cmnuSelMe = _cmnuSelMe;

    var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
    var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;

    var left = event.clientX + scrollLeft;
    var top = event.clientY + scrollTop;

    pmnu.style.display = 'block';

    var mnuoffset = screen.width - (left + pmnu.offsetWidth + 5);
    if (mnuoffset < 0) left = left - pmnu.offsetWidth;

    mnuoffset = screen.height - (top + 180 + pmnu.offsetHeight);
    if (mnuoffset < 0) top = top + mnuoffset;

//    switch(pmnu.id)
//    {
//        case "mnuUser": //128
//
//            break;
//
//        case "mnuHost": //312
//            break;
//
//        case "mnuHelpOp": //186
//            break;
//    }


    //fnAppendText("Left: " + left + ", Top: " + top + ", WndLeft: " + screen.width + ", WndTop: " + screen.height + ", mnuHeight: " + pmnu.offsetHeight + ", menuOffset: " + mnuoffset);

    pmnu.style.left = left + 'px';
    pmnu.style.top = top + 'px';
    //pmnu.style.display = 'block';
    //pmnu.tabIndex = 0;
    gNewFocus = pmnu;
    setTimeout("setFocus();", 0);
}

function closeAllMenus()
{
    _mnuitemselected = false;
    //debugOutput("cmnuSelMe: " + cmnuSelMe, "closeAllMenus");
    cmnuSelMe = false;

    if (prevmnuselected != null)
    {
        unselectMnuItem(prevmnuselected);
        prevmnuselected = null;
    }

    closeMenu(_pmnucp);
    closeMenu(_pmnuhost);
    closeMenu(_pmnuhelpop);
    closeMenu(_pmnuuser);
}

function closeMenu(pmnu)
{
    //pmnu.tabIndex = 0;
    if (pmnu) pmnu.style.display = 'none';
}

function fnMnuDisable(disable, pmnu)
{
    try
    {
        if (disable == false)
        {
            pmnu.disabled = false;
            pmnu.style.color = '#000000';
        }
        else
        {
            pmnu.disabled = true;
            pmnu.style.color = '#808080';
        }
    }
    catch (ex)
    {
        debugOutput(ex, 'fnMnuDisable');
    }
}

//something doesn't seem right this function and unselect for LVI, and move this fn to right place
function SelectLocalUser()
{
    if (olvUsers.selectedUser() != null) olvUsers.unselectLVI(olvUsers.selectedLVI());

    plbMe.className = 'lvuitemlbMeSel';
    gNewFocus = plbMe;
    setTimeout("setFocus();", 0);
}

function getMenu(el)
{
    //debugger;
    var icount = 0;
    while((el != null) && (icount < 5))
    {
        icount++;
        switch (el.id.substring(0, 3))
        {
            case 'txS':
                return 'true';

            case 'cpb':
                return _pmnucp;

            case 'lvi':
                onListUserSelect(_clvicmnu, false);
                return _clvicmnu;
            case 'lbM':
                onListUserSelect(_clvicmnu, true);
                cmnuSelMe = true;
                SelectLocalUser();
                return _clvicmnu;
            default:
                if (el.id.indexOf("mi") == 0) return null;
                //if (el.id.indexOf("lbMe") == 0 //add this one if there are other ids starting with 'lbM';
                //checked there is none starting with 'lbM', but add it in developor notes so nobody adds more
                break;
        }

        el = el.parentNode;
    }

    return null;
}

function onListUserSelect(pmnu, lumnu)
{
    var puser = null;

    if (lumnu == false) puser = olvUsers.selectedUser();
    else puser = ouserMe;

    if (puser != null)
    {
        switch (pmnu.id)
        {
            case 'mnuUser':
                onMnuUser(lumnu);
                break;

            case 'mnuHelpOp':
                onMnuHelpOp(lumnu);
                break;

            case 'mnuHost':
                onMnuHost(lumnu);
                break;
        }
    }
}

function onMnuUser(lumnu)
{
    var puser = null;

    if (lumnu == false) puser = olvUsers.selectedUser();
    else puser = ouserMe;

    if (puser != null)
    {
        //view profile menuitem
        if (puser.nick.indexOf(">") == 0) fnMnuDisable(true, _pmiVPU);
		else fnMnuDisable(false, _pmiVPU);

		//whisper menuitem
		if (lumnu == false)
		{
		    if ((Modes[0].indexOf("w") >= 0 || Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && (ouserMe.voice == false || puser.voice == false) && puser.ilevel < IsHelpOp))
		    {
			    //miWhisper.enabled = false;
			    fnMnuDisable(true, _pmiWU);
		    }
		    else if ((Modes[0].indexOf("W") >= 0) && (ouserMe.nick.charAt(0) == ">" || puser.nick.charAt(0) == ">") && (ouserMe.ilevel < IsHelpOp && puser.ilevel < IsHelpOp))
		    {
			    fnMnuDisable(true, _pmiWU);
		    }
		    else fnMnuDisable(false, _pmiWU);
		}
		else fnMnuDisable(true, _pmiWU);

		//ignore menuitem
		if (puser.ignore == true) _pmiIU.innerHTML = lang['menuitem_ignore_true'];
		else _pmiIU.innerHTML = lang['menuitem_ignore_false'];

        if (puser.ilevel > IsSuperOwner || lumnu == true) fnMnuDisable(true, _pmiIU);
        else fnMnuDisable(false, _pmiIU);

        //tag menuitem
        if (puser.tagged == true) _pmiTUU.innerHTML = lang['menuitem_tagged_true'];
		else _pmiTUU.innerHTML = lang['menuitem_tagged_false'];

		//localtime menuitem
        if (ouserMe.voice == false && (Is_m_Mode == true || Is_x_Mode == true)) fnMnuDisable(true, _pmiLTU);
        else fnMnuDisable(false, _pmiLTU);

		//awaymsg menu
        if (puser.away == true) fnMnuDisable(false, _pmiAMU);
        else fnMnuDisable(true, _pmiAMU);
    }
}

function onMnuHelpOp(lumnu)
{
    var puser = null;

    if (lumnu == false) puser = olvUsers.selectedUser();
    else puser = ouserMe;

    if (puser != null)
    {
        //view profile menuitem
        if (puser.nick.indexOf(">") == 0) fnMnuDisable(true, _pmiVPHO);
		else fnMnuDisable(false, _pmiVPHO);

		//whisper menuitem
		if (lumnu == false)
		{
		    if ((Modes[0].indexOf("w") >= 0 || Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && (ouserMe.voice == false || puser.voice == false) && puser.ilevel < IsHelpOp))
		    {
			    //miWhisper.enabled = false;
			    fnMnuDisable(true, _pmiWHO);
		    }
		    else if ((Modes[0].indexOf("W") >= 0) && (ouserMe.nick.charAt(0) == ">" || puser.nick.charAt(0) == ">") && (ouserMe.ilevel < IsHelpOp && puser.ilevel < IsHelpOp))
		    {
			    fnMnuDisable(true, _pmiWHO);
		    }
		    else fnMnuDisable(false, _pmiWHO);
		}
		else fnMnuDisable(true, _pmiWHO);

		//ignore menuitem
		if (puser.ignore == true) _pmiIHO.innerHTML = lang['menuitem_ignore_true'];
		else _pmiIHO.innerHTML = lang['menuitem_ignore_false'];

        if (puser.ilevel > IsSuperOwner || lumnu == true) fnMnuDisable(true, _pmiIHO);
        else fnMnuDisable(false, _pmiIHO);

        //tag menuitem
        if (puser.tagged == true) _pmiTUHO.innerHTML = lang['menuitem_tagged_true'];
		else _pmiTUHO.innerHTML = lang['menuitem_tagged_false'];

		//localtime menuitem
        //if (ouserMe.voice == false && (Is_m_Mode == true || Is_x_Mode == true)) fnMnuDisable(true, _pmiLTHO);
        //else fnMnuDisable(false, _pmiLTHO);

		//awaymsg menuitem
        if (puser.away == true) fnMnuDisable(false, _pmiAMHO);
        else fnMnuDisable(true, _pmiAMHO);

        //kick, voice menuitem
        mySLev = getSimpleLevel(ouserMe);
        ouSLev = getSimpleLevel(puser);

        if (mySLev < ouSLev)
        {
            fnMnuDisable(true, _pmiVHO);
            fnMnuDisable(true, _pmiKHO);
            fnMnuDisable(true, _pmiPHO);
        }
        else
        {
            fnMnuDisable(false, _pmiVHO);

            if (lumnu == false) fnMnuDisable(false, _pmiKHO);
            else fnMnuDisable(true, _pmiKHO);

            if (puser.ilevel >= IsHelpOp) fnMnuDisable(false, _pmiPHO);
            else fnMnuDisable(true, _pmiPHO);
        }
    }
}

function onMnuHost(lumnu)
{
    var puser = null;

    if (lumnu == false) puser = olvUsers.selectedUser();
    else puser = ouserMe;

    if (puser != null)
    {
        //view profile menuitem
        if (puser.nick.indexOf(">") == 0) fnMnuDisable(true, _pmiVPH);
		else fnMnuDisable(false, _pmiVPH);

		//whisper menuitem
		if (lumnu == false)
		{
		    if ((Modes[0].indexOf("w") >= 0 || Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && (ouserMe.voice == false || puser.voice == false) && puser.ilevel < IsHelpOp))
		    {
			    fnMnuDisable(false, _pmiWH);
		    }
		    else if ((Modes[0].indexOf("W") >= 0) && (ouserMe.nick.charAt(0) == ">" || puser.nick.charAt(0) == ">") && (ouserMe.ilevel < IsHelpOp && puser.ilevel < IsHelpOp))
		    {
			    fnMnuDisable(true, _pmiWH);
		    }
		    else fnMnuDisable(false, _pmiWH);
		}
		else fnMnuDisable(true, _pmiWH);

		//ignore menuitem
		if (puser.ignore == true) _pmiIH.innerHTML = lang['menuitem_ignore_true'];
		else _pmiIH.innerHTML = lang['menuitem_ignore_false'];

        if (puser.ilevel > IsSuperOwner || lumnu == true) fnMnuDisable(true, _pmiIH);
        else fnMnuDisable(false, _pmiIH);

        //tag menuitem
        if (puser.tagged == true) _pmiTUH.innerHTML = lang['menuitem_tagged_true'];
		else _pmiTUH.innerHTML = lang['menuitem_tagged_false'];

		 //localtime menuitem
        //if (ouserMe.voice == false && (Is_m_Mode == true || Is_x_Mode == true)) fnMnuDisable(true, _pmiLTH);
        //else fnMnuDisable(false, _pmiLTH);

		//awaymsg menuitem
        if (puser.away == true) fnMnuDisable(false, _pmiAMH);
        else fnMnuDisable(true, _pmiAMH);

        //kick, voice menuitem
        mySLev = getSimpleLevel(ouserMe);
        ouSLev = getSimpleLevel(puser);

        if (mySLev < ouSLev)
        {
            fnMnuDisable(true, _pmiKH);
            fnMnuDisable(true, _pmiB15mH);
            fnMnuDisable(true, _pmiB1hH);
            fnMnuDisable(true, _pmiB24hH);

            fnMnuDisable(true, _pmiVH);
            fnMnuDisable(true, _pmiPH);
            fnMnuDisable(true, _pmiHOH);
            fnMnuDisable(true, _pmiHH);
            fnMnuDisable(true, _pmiOH);
        }
        else
        {
            if (lumnu == false)
            {
                fnMnuDisable(false, _pmiKH);
                fnMnuDisable(false, _pmiB15mH);
                fnMnuDisable(false, _pmiB1hH);
                fnMnuDisable(false, _pmiB24hH);
            }
            else
            {
                fnMnuDisable(true, _pmiKH);
                fnMnuDisable(true, _pmiB15mH);
                fnMnuDisable(true, _pmiB1hH);
                fnMnuDisable(true, _pmiB24hH);
            }

            fnMnuDisable(false, _pmiVH);

            //user op modes menu items
            if (puser.ilevel >= IsSuperOwner)
            {
                fnMnuDisable(true, _pmiPH);
                fnMnuDisable(true, _pmiHOH);
                fnMnuDisable(true, _pmiHH);
                fnMnuDisable(true, _pmiOH);
            }
            else
            {
                fnMnuDisable(false, _pmiHOH);
                fnMnuDisable(false, _pmiHH);

                if (puser.ilevel >= IsHelpOp) fnMnuDisable(false, _pmiPH);
                else fnMnuDisable(true, _pmiPH);

                //owner mode menuitem
                if (ouserMe.ilevel < IsOwner) fnMnuDisable(true, _pmiOH);
                else fnMnuDisable(false, _pmiOH);
            }
        }
    }
}

function getSimpleLevel(puser)
{
    var slev = 0;

    if ((puser.ilevel & IsStaff) == IsStaff) slev = 5;
	else if ((puser.ilevel & IsSuperOwner) == IsSuperOwner) slev = 4;
	else if ((puser.ilevel & IsOwner) == IsOwner) slev = 3;
	else if ((puser.ilevel & IsHost) == IsHost) slev = 2;
	else if ((puser.ilevel & IsHelpOp) == IsHelpOp) slev = 1;
	else slev = 0;

	return slev;
}

function updateLVIMenu()
{
    if ((ouserMe.ilevel & IsStaff) == IsStaff) _clvicmnu = _pmnuhost;
	else if ((ouserMe.ilevel & IsSuperOwner) == IsSuperOwner) _clvicmnu = _pmnuhost;
	else if ((ouserMe.ilevel & IsOwner) == IsOwner) _clvicmnu = _pmnuhost;
	else if ((ouserMe.ilevel & IsHost) == IsHost) _clvicmnu = _pmnuhost;
	else if ((ouserMe.ilevel & IsHelpOp) == IsHelpOp) _clvicmnu = _pmnuhelpop;
	else _clvicmnu = _pmnuuser;
}

function cmenuShow(event)
{
    //return true;
    
    if (event == null) event = getEventObject();

    if (IsCPTextSelected()) fnMnuDisable(false, _pMnuCopy);
    else fnMnuDisable(true, _pMnuCopy);

    var target = event.target != null ? event.target : event.srcElement;

    var pmnu = getMenu(target);

    if (pmnu != null)
    {
        if (pmnu == 'true') return true;
        showMenu(pmnu, event);
     }

    return false;
}

function iniContextMenu()
{
    _pmnucp = getById('cmenuCP'); _pmnuhost = getById('mnuHost'); _pmnuhelpop = getById('mnuHelpOp'); _pmnuuser = getById('mnuUser');

    _pwndChat = getById('wndChat');
    _pcpbody = (isIE) ? ChatPane.document.body : pChatPane.contentDocument.body;

    _pMnuCopy = getById('mnuCpCopy');
    _pmiVPU = getById('miVPU'); _pmiWU = getById('miWU'); _pmiIU = getById('miIU'); _pmiTUU = getById('miTUU'); _pmiLTU = getById('miLTU'); _pmiAMU = getById('miAMU');
    _pmiVPHO = getById('miVPHO'); _pmiWHO = getById('miWHO'); _pmiIHO = getById('miIHO'); _pmiTUHO = getById('miTUHO'); _pmiLTHO = getById('miLTHO'); _pmiAMHO = getById('miAMHO'); _pmiVHO = getById('miVHO'); _pmiPHO = getById('miPHO'); _pmiKHO = getById('miKHO');
    _pmiVPH = getById('miVPH'); _pmiWH = getById('miWH'); _pmiIH = getById('miIH'); _pmiTUH = getById('miTUH'); _pmiLTH = getById('miLTH'); _pmiAMH = getById('miAMH'); _pmiKH = getById('miKH'); _pmiB15mH = getById('miB15mH'); _pmiB1hH = getById('miB1hH'); _pmiB24hH = getById('miB24hH'); _pmiVH = getById('miVH'); _pmiPH = getById('miPH'); _pmiHOH = getById('miHOH'); _pmiHH = getById('miHH'); _pmiOH = getById('miOH')
    //alert(_pcpbody.id);

    if (_pMnuCopy.disabled == undefined) _pMnuCopy.disabled = false;

    if (_pmiVPU.disabled == undefined) _pmiVPU.disabled = false;
    if (_pmiWU.disabled == undefined) _pmiWU.disabled = false;
    if (_pmiIU.disabled == undefined) _pmiIU.disabled = false;
    //if (_pmiTUU.disabled == undefined) _pmiTUU.disabled = false;
    if (_pmiLTU.disabled == undefined) _pmiLTU.disabled = false;
    if (_pmiAMU.disabled == undefined) _pmiAMU.disabled = false;

    if (_pmiVPHO.disabled == undefined) _pmiVPHO.disabled = false;
    if (_pmiWHO.disabled == undefined) _pmiWHO.disabled = false;
    if (_pmiIHO.disabled == undefined) _pmiIHO.disabled = false;
    //if (_pmiTUHO.disabled == undefined) _pmiTUHO.disabled = false;
    if (_pmiLTHO.disabled == undefined) _pmiLTHO.disabled = false;
    if (_pmiAMHO.disabled == undefined) _pmiAMHO.disabled = false;
    if (_pmiVHO.disabled == undefined) _pmiVHO.disabled = false;
    if (_pmiPHO.disabled == undefined) _pmiPHO.disabled = false;
    if (_pmiKHO.disabled == undefined) _pmiKHO.disabled = false;

    if (_pmiVPH.disabled == undefined) _pmiVPH.disabled = false;
    if (_pmiWH.disabled == undefined) _pmiWH.disabled = false;
    if (_pmiIH.disabled == undefined) _pmiIH.disabled = false;
    //if (_pmiTUH.disabled == undefined) _pmiTUH.disabled = false;
    if (_pmiLTH.disabled == undefined) _pmiLTH.disabled = false;
    if (_pmiAMH.disabled == undefined) _pmiAMH.disabled = false;
    if (_pmiKH.disabled == undefined) _pmiKH.disabled = false;
    if (_pmiB15mH.disabled == undefined) _pmiB15mH.disabled = false;
    if (_pmiB1hH.disabled == undefined) _pmiB1hH.disabled = false;
    if (_pmiB24hH.disabled == undefined) _pmiB24hH.disabled = false;
    if (_pmiVH.disabled == undefined) _pmiVH.disabled = false;
    if (_pmiPH.disabled == undefined) _pmiPH.disabled = false;
    if (_pmiHOH.disabled == undefined) _pmiHOH.disabled = false;
    if (_pmiHH.disabled == undefined) _pmiHH.disabled = false;
    if (_pmiOH.disabled == undefined) _pmiOH.disabled = false;

    _pwndChat.onmousedown = onMouseDown;
    _pwndChat.oncontextmenu = cmenuShow;
    _pcpbody.onmousedown = onMouseDown;
    _pcpbody.oncontextmenu = cmenuShow;

    //debugOutput("meObj TypeOf: " + typeof(ouserMe), "iniContextMenu");
    updateLVIMenu();
}
//---- </menu>

//---- < UI >
var pBtnWhisp = null, pBtnIgnore = null, pBtnTag = null, pBtnViewProfile = null, pBtnSend = null, pBtnAction = null;

function UpdateBtnImage(pbtn, imgsrc)
{
    //alert(imgsrc);
    pbtn.src = imgsrc;
}

function iniUIObjects()
{
    pBtnWhisp = getById('btnWhisp');
    pBtnIgnore = getById('btnIgnore');
    pBtnTag = getById('btnTag');
    pBtnViewProfile = getById('btnViewProfile');
//    pBtnSend = getById('btnWhisp');
//    pBtnAction = getById('btnWhisp');

    pBtnWhisp.disable = true;
    pBtnIgnore.disable = true;
    pBtnTag.disable = true;
    pBtnViewProfile.disable = true;
}

function UpdateUI(puser)
{
    //view profile menuitem
    if (puser.nick.indexOf(">") == 0)
    {
        pBtnViewProfile.disable = true;
        UpdateBtnImage(pBtnViewProfile,  sFUIDIR + '/Chat_files/profie_icon_grey.gif');
    }
	else
	{
	    pBtnViewProfile.disable = false;
	    UpdateBtnImage(pBtnViewProfile,  sFUIDIR + '/Chat_files/profie_icon.gif');
	}

    //whisper button
	if ((Modes[0].indexOf("w") >= 0 || Is_m_Mode == true || Is_x_Mode == true) && (ouserMe.ilevel < IsHelpOp && (ouserMe.voice == false || puser.voice == false) && puser.ilevel < IsHelpOp))
	{
	    pBtnWhisp.disable = false;
		UpdateBtnImage(pBtnWhisp,  sFUIDIR + '/Chat_files/whisper.gif');
	}
	else if ((Modes[0].indexOf("W") >= 0) && (ouserMe.nick.charAt(0) == ">" || puser.nick.charAt(0) == ">") && (ouserMe.ilevel < IsHelpOp && puser.ilevel < IsHelpOp))
	{
	    pBtnWhisp.disable = true;
		UpdateBtnImage(pBtnWhisp,  sFUIDIR + '/Chat_files/whisper_grey.gif');
	}
	else
	{
	    pBtnWhisp.disable = false;
	    UpdateBtnImage(pBtnWhisp,  sFUIDIR + '/Chat_files/whisper.gif');
	}

	//ignore button
	if (puser.ilevel > IsSuperOwner)
	{
	    pBtnIgnore.disable = true;
	    UpdateBtnImage(pBtnIgnore,  sFUIDIR + '/Chat_files/iggy_grey.gif');
	}
    else
    {
        pBtnIgnore.disable = false;
        UpdateBtnImage(pBtnIgnore,  sFUIDIR + '/Chat_files/iggy.gif');
    }

    //tag button
    UpdateBtnImage(pBtnTag,  sFUIDIR + '/Chat_files/tag.gif');
    pBtnTag.disable = false;
}

function onBtnViewProfile()
{
    fnViewProfile();
}

function onBtnWhisp()
{
    OpenWhisperWindow();
}

function onBtnIgnore()
{
    fnIgnore();
}

function onBtnTag()
{
    fnTag();
}

function onBtnAction()
{
    if (ptxSend.value.length > 0)
	{
	    if (IsSendable())
	    {
	        fnAction(ptxSend.value);
	        fnNewInputMessage(ptxSend.value);
	        ptxSend.value = ""; idxInputMessages = null;
	    }
	}
}

var idxInputMessages = null;
var sTmpInputMsg = '', IsTempMsgActive = false;
function onTxSendKeypress(ev)
{
    if (ev == null) ev = window.event;
    var bLoadBlankText = false, bWasNull = false;

     try
     {
        if (stkInputMessages.length > 0)
        {
            if (idxInputMessages == null)
            {
                idxInputMessages = (stkInputMessages.length - 1);
                bWasNull = true;
            }

            if (ev.keyCode == KEY_DOWN)
            {
                if (idxInputMessages < (stkInputMessages.length - 1))
                {
                    idxInputMessages++;
                }
                else
                {
                    bLoadBlankText = true;
                    idxInputMessages = null;
                }
            }
            else if (ev.keyCode == KEY_UP)
            {
                if (idxInputMessages > 0 && IsTempMsgActive) idxInputMessages--;
                else
                {
                    if (!bWasNull && idxInputMessages == 0) return false;
                }
                if (idxInputMessages == (stkInputMessages.length - 1) && !IsTempMsgActive)
                {
                    sTmpInputMsg = ptxSend.value;
                    IsTempMsgActive = true;
                }
            }
            else return false;

            if (!bLoadBlankText) ptxSend.value = stkInputMessages[idxInputMessages];
            else
            {
                ptxSend.value = sTmpInputMsg;
                IsTempMsgActive = false;
            }
        }
     }
     catch(ex)
    {
        debugOutput(ex, 'onTxSendKeypress');
    }

    return false;
}

function showGuestLoginDialog()
{


    if (pwndGLD.style.display != 'block')
    {
        ptxGLN.value = "Enter_Your_Nickname_Here";
        strGuestPass = flashObj.GetGuestuserPass();
        //ppwGuest.value = flashObj.GetGuestuserPass();
        //fnAppendText(ppwGuest.value);
        ptxGLDErrorMessage.value = "";

        var cwidth = 200;
        var cheight = 100;
        var LeftPosition = (screen.width) ? (screen.width-cwidth)/2 : 0;
        var TopPosition = (screen.height) ? (screen.height-cheight)/2 : 0;

        pwndGLD.style.left = LeftPosition + 'px';
        pwndGLD.style.top = TopPosition + 'px';
        pwndGLD.style.display = 'block';
    }
}

function onGuestLoginDialogReturn()
{
    var sGNick = ptxGLN.value;

    if (sGNick.length > 2)
    {
        pwndGLD.style.display = 'none';
        if (sGNick[0] != '>') sGNick =  '>' + sGNick;
        flashObj.SetGuestInfo(sGNick, strGuestPass);
        IsGuestInfoSet = true;
        fnConnect();
    }
    else
    {
        ptxGLDErrorMessage.innerHTML = "* Nickname must be more than 2 characters.";
    }
}
//---- </ UI >

//---- Misc.
function fnViewProfile()
{
//debugger;
//debugOutput("cmnuSelMe: " + cmnuSelMe, "fnViewProfile");
    if (cmnuSelMe == false)
    {
        if (pBtnViewProfile.disable != true)
        {
            if (olvUsers.selectedUser() == null) return;
            var cmdGetProfile = "PID " + olvUsers.selectedUser().nick;
	        flashObj.sendToServer(cmdGetProfile);
	    }
	}
	else
	{
	    var cmdGetProfile = "PID " + ouserMe.nick;
	    flashObj.sendToServer(cmdGetProfile);
	}
}

var asaIgnoreHashTbl = new Array();

function fnAddIdentToIgnoreHash(ident) {
    asaIgnoreHashTbl[ident] = 1;
}

function fnRemIdentFromIgnoreHash(ident) {
    delete asaIgnoreHashTbl[ident];
}

function fnProcessUserIdentIngnore(plvi) {

    if (asaIgnoreHashTbl[plvi.pUser.ident] == 1) {
        plvi.pUser.ignore = true;
        formatUserLabel(plvi.pUser, plvi.pLabel);
        updateUserIcon(plvi.pUser, plvi.pIco, plvi.pLabel);
    }
}

function fnIgnore()
{
    if (pBtnIgnore.disable != true)
    {
        var plvi = olvUsers.selectedLVI();
        if (plvi == null) return;

        if (plvi.pUser.ignore == false)
	    {
	        plvi.pUser.ignore = true;
	        fnAddIdentToIgnoreHash(plvi.pUser.ident);
	    }
	    else
	    {
	        plvi.pUser.ignore = false;
	        fnRemIdentFromIgnoreHash(plvi.pUser.ident);
	    }

	    formatUserLabel(plvi.pUser, plvi.pLabel);
	    updateUserIcon(plvi.pUser, plvi.pIco, plvi.pLabel);
	}
}

function fnTag()
{
    //debugger;
    if (cmnuSelMe == false)
    {
        var plvi = olvUsers.selectedLVI();
        if (plvi == null) return;

        if (plvi.pUser.tagged == false)
	    {
		    plvi.pUser.tagged = true;
		    addTag(plvi.pUser.nick);
	    }
	    else
	    {
		    plvi.pUser.tagged = false;
		    removeTag(plvi.pUser.nick);
	    }

	    formatUserLabel(plvi.pUser, plvi.pLabel);
	    updateUserIcon(plvi.pUser, plvi.pIco, plvi.pLabel);
	}
	else
	{
	    if (ouserMe.tagged == false)
	    {
		    ouserMe.tagged = true;
		    addTag(ouserMe.nick);
	    }
	    else
	    {
		    ouserMe.tagged = false;
		    removeTag(ouserMe.nick);
	    }

	    formatUserLabel(ouserMe, plbMe);
	    updateUserIcon(ouserMe, puicoMe, plbMe);
	}
}

var wndChatOptions = null;

function OpenChatOptionsWnd()
{
    if (wndChatOptions == null || wndChatOptions.closed == true)
    {
        wndChatOptions = window.open(sFUIDIR2 + 'wndChatOptions.htm', 'wndChatOptions', 'left=50,top=50,width=572,height=400,toolbar=0,resizable=1,directories=0,status=yes,menubar=0,scrollbars=1,titlebar=0,location=0');
    }
    else
    {
        wndChatOptions.focus();
    }
}
// helper functions
function IsNum(v0)
{
    try
    {
        var v1 = new String(v0);
        var regex = /[^0-9]/;

        return !regex.test(v1);
    }
    catch (ex)
    {
        debugOutput(ex);
    }
}

//---- Test
function fnStat()
{
    alert('loopcount: '+loopcount);
}

function fnUpdate()
{
    try
    {
//        var ptxRNum = getById('txRNum');
//        var ptxNN = getById('txNewNick');

//        var val = ptxRNum.value;
//        var val2 = ptxNN.value;
//        //debugOutput(pWndWhisp.name);
//        //wndWhisp.pwnd.CrossWindowMessage('my message');

////        if (IsNum(val)) olvUsers.removeItemById(val);
////        else olvUsers.removeItemByName(val);

//    _pcpbody.style.fontSize = val;
//    alert(_pcpbody.style.fontSize);

alert(ChatPane.document.body.scrollHeight);
//        switch (val)
//        {
//            case 'large':
//                //_pcpbody.fontSize = 'large';
//                break;
//        }
    }
    catch (ex)
    {
        debugOutput(ex, 'fnUpdate()');
    }
}

function LoadDummyUsers()
{
    try
    {
        ouserMe = {nick:null, ident:null, host:null, ilevel:IsStaff, iprofile:NoProfile, away:false, awaymsg:"", voice:false};
        onAddUser({nick:'^Staff', ident:null, host:null, ilevel:IsStaff, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'SuperOwner', ident:null, host:null, ilevel:IsSuperOwner, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'Owner', ident:null, host:null, ilevel:IsOwner, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'Host', ident:null, host:null, ilevel:IsHost, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'HelpOp', ident:null, host:null, ilevel:IsHelpOp, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'NoProfile', ident:null, host:null, ilevel:0, iprofile:NoProfile, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'NoGender', ident:null, host:null, ilevel:0, iprofile:NoGender, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'NoGenderWPic', ident:null, host:null, ilevel:0, iprofile:NoGenderWPic, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'Female', ident:null, host:null, ilevel:0, iprofile:Female, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'FemaleWPic', ident:null, host:null, ilevel:0, iprofile:FemaleWPic, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'Male', ident:null, host:null, ilevel:0, iprofile:Male, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'MaleWPic', ident:null, host:null, ilevel:0, iprofile:MaleWPic, away:false, awaymsg:"", voice:false});
        onAddUser({nick:'MaleWPica', ident:null, host:null, ilevel:0, iprofile:MaleWPic, away:true, awaymsg:"", voice:false});
    }
    catch (ex)
    {
        debugOutput(ex, 'LoadDummyUsers()');
    }
}
