﻿function ltrim(str)
{
  return str.replace(/^\s+/g, '');
}

function alltrim(str)
{
  return str.replace(/(^\s+)|(\s+$)/g, '');
}

function watson(message, url, lineNumber)
{
    try
    {
        if (url == null || url == '') url = window.location; // url is empty for exceptions in FF
        
        var errorText = '' + message + ' at ' + url + '(' + lineNumber + ')';
        
        // @TODO: should we not ask for confirmation?
        var send = confirm( 'Web application experienced a problem:\n\n    ' +
            errorText +
            '\n\nClick OK to send error report to Memengo, Inc. and to help to improve the service.');
        
        if (!send) return true;
        
        var http = window.XMLHttpRequest ? new XMLHttpRequest() : ( window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : null );
        if (http == null) return true;
        
        var firebug = window.console ? ("firebug:" + window.console.firebug + "\n") : null; 
        var loc = document.location;
        var siteRoot = (loc.href.indexOf("/_siteroot_")==-1 && loc.href.indexOf("/%5Fsiteroot%5F")==-1) ? "" : "/_siteroot_";
        var postTarget = loc.protocol + "//" + loc.host + siteRoot + '/M7Data.aspx?log_only=true';
        http.open('POST', postTarget);
        http.send('WEB_SITE_WATSON:\n' + firebug + errorText);
        
        // @TODO: recovery? navigate to homepage?
    }
    catch(e)
    {
    }
    
    return true;
}

window.onerror = watson;

function focusElement(e, async, noSelect)
{
    if (async)
    {
        setTimeout(function() {focusElement(e,false,noSelect);}, 0);
        return true;
    }
    
    try
    {
        e = $(e);
        if (e.setActive) e.setActive();
        e.focus();
        if (!noSelect && e.select) e.select();
    }
    catch(ex)
    {
        return false;
    }
    
    return true;
}

function swapDisplayStyle(e)
{
    e = $(e);
    e.style.display = e.style.display.toLowerCase() == 'none' ? '' : 'none';
}

// recursvely travers all descendant HTML nodes and if one has ID, assign to it new ID is OldID + ' : " + extra number (strExtraID) passed in. 
function PatchIDs(hnode, obj, strExtraID)
{
    var strOldID = hnode.id;
    if (strOldID!=null && strOldID!="")
    {
        var strNewID = strOldID + ":" + strExtraID;
        hnode.id = strNewID;
        obj[strOldID] = document.getElementById(strNewID);
    }
        
    if (hnode.firstChild != null)
    {
        for (var i in hnode.childNodes)
        {
            PatchIDs(hnode.childNodes[i], obj, strExtraID);
        }
    }
    return hnode;
}

// find all IDs and save them to the objects
function RememberIDs(hnode, obj, fClearIds)
{
    var strOldID = hnode.id;
    if (strOldID!=null && strOldID!='')
    {
        obj[strOldID] = hnode;
        if (fClearIds) 
        {   
            hnode.id = null;
        }
    }
        
    if (hnode.firstChild != null)
    {
        for (var i in hnode.childNodes)
        {
            RememberIDs(hnode.childNodes[i], obj, fClearIds);
        }
    }
}

// in a html subtree previously patched by PatchIDs detect strExtraID and locate object that has same ID.
function GetCurrentObject(hnode, strType)
{
  for(var hnode2=hnode; hnode2!=null && hnode2.tagName.toLowerCase()!="body"; hnode2=hnode2.parentNode)
  {
    var iNum = GetCurrNumber(hnode2.id);
    if (iNum==null)
      continue;
    var obj = g_StoreClient.m_hashObjects[iNum];
    if (obj!=null)
      return obj;
  }
  return null;
}

function FindNearestAncestor(hnodeStart, strTagName)
{
  var hnode = null;
  for(hnode = hnodeStart; hnode!=null && hnode.tagName.toLowerCase()!=strTagName; hnode=hnode.parentNode)
  {
  }
  return hnode;
}

function GetCurrNumber(str)
{
  if (str==null || str=='')
    return null;
  var rgSplit = str.split(":");
  if (rgSplit.length<=1)
    return null;
  var strNum = rgSplit[1];
  if (strNum=="")
    return null;
  return strNum;
}
function GetCurrentFolder(hnode)
{
  return GetCurrentObject(hnode, "FLDR");
}
function GetCurrentSecret(hnode)
{
  return GetCurrentObject(hnode, "ITEM");
}

function SetInnerText(hnode, str)
{
  hnode.innerText = hnode.textContent = str;
}

//Breadth-first recursive search for any node that has ID equal to supplied strHID.
function FindHnodeByID(hnodeRoot, strHID)
{
  if (hnodeRoot==null)
    return null;
  for(var i=0;i<hnodeRoot.childNodes.length;i++)
  {
    var hnodeCurr = hnodeRoot.childNodes[i];
    if (typeof hnodeCurr.id != 'undefined' && hnodeCurr.id == strHID)
      return hnodeCurr;
  }
  for(var i=0;i<hnodeRoot.childNodes.length;i++)
  {
    var hnodeCurr = hnodeRoot.childNodes[i];
    var hnodeResult = FindHnodeByID(hnodeCurr, strHID);
    if (hnodeResult!=null)
      return hnodeResult;
  }
  return null;
}

function DestroyAllChildElements(hnode)
{
  for (var i=hnode.childNodes.length; i>0; i--)
    hnode.removeChild(hnode.childNodes[i-1]);
}

function UnescaperFunc(x) 
{
  var hshUnescape = {'^^':'^', '^1':'|', '^2':'\n'};
  return hshUnescape[x];
};
function RgSplitAndUnescapeString(str)
{
  if (str==null || str=='')
     return null;
  var rg = str.split('|');
  for (var i in rg)
  {
    var strEscaped = rg[i];
    var strUnescaped = strEscaped.replace(/(\^\^)|(\^1)|(\^2)/g, UnescaperFunc);
    rg[i] = strUnescaped;
  }
 return rg;
}

function EscaperFunc(x) 
{ 
  var hshEscape = {'^':'^^', '|':'^1', '\r\n':'^2', '\n':'^2'};
  return hshEscape[x];
};

function EscapeAndJoinArray(rg)
{
  if (rg==null || rg.length==0)
    return null;
  for (var i in rg)
  {
    var strEscapedValue = rg[i].replace(/(\|)|(\^)|(\r\n)/g, EscaperFunc);
    rg[i] = strEscapedValue;
  }
  var strResult = rg.join('|');
  return strResult;
}

function GetErrorMessageByCode(code)
{
  var x = g_AllResponses[code];
  if (x==null)
     return 'code:'+code.toString();
  return x.m_strMessage;
}

function CopyHash2Array(rgIn)
{
  var rgOut = new Array();
  for (var i in rgIn)
    rgOut.push(rgIn[i]);
  return rgOut;
}

function isObjectEmpty(obj)
{
    for (var i in obj)
    {
        if (obj[i] != null)
        {
            return false;
        }
    }
    return true;
}

function htmlEncode(str)
{
    var r = [];
    var c;
    for (var i = 0; i < str.length; ++i)
    {
        c = str.charCodeAt(i);
        if (c == 34) //"
            r.push('&quot;');
        else if (c == 60) //<
            r.push('&lt;');
        else if (c == 62) //>
            r.push('&gt;');
        else if (c == 38) //&
            r.push('&amp;');
        else if (c == 10) //\n
            r.push('<br/>\n');
        else if (c == 8) //\t
            r.push('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
        else if (c == 32) //space
            r.push('&nbsp;');
        else if (c < 32 || c > 126)
            r.push('&#' + c + ';');
        else
            r.push(str.charAt(i));    
    }
    return r.join('');
}

function GetNextElement(xe)
{
  if (xe==null)
    return null;
  return GetFirstElement(xe.nextSibling);
}

function GetFirstElement(xe)
{
  var xer = xe;
  while((xer!=null) && (xer.nodeType!=1))
  {
    xer = xer.nextSibling;
  }
  return xer;
}

function SerializeJSON7(obj)
{
  var strQ ='"', strQ2 ="'", strQuotes='""', strQuotes2="''", strComma=',', strColon=':', strEmpty='', strLBr='[', strRBr=']', strLCr='{',strRCr='}', strU2='\\u00', strU3='\\u000';
  var rxBadChars = new RegExp("[\\x00-\\x1f\'\\\\]", 'g');
  var chrMap = {
    "\'" : "\\'",
    '\\' : '\\\\',
    '\/' : '\\/',
    '\b' : '\\b',
    '\f' : '\\f',
    '\n' : '\\n',
    '\r' : '\\r',
    '\t' : '\\t'
  };
  function FuncReplacer(chr)
  {
    var r = chrMap[chr];
    if (r!=null)
      return r;
    var chrCode = chr.charCodeAt(0);
    var r = chrCode.toString(16);
    if (r.length==1)
      r = strU3 + r;
    else
      r = strU2 + r;
    return r;
  }
  function EscapeString(str)
  {
    if (rxBadChars.test(str))
      str = str.replace(rxBadChars, FuncReplacer)
    return strQ2+str+strQ2;
  }

  function Recurse(obj)
  {
    if (obj==null)
      return strQuotes2;
    if (obj instanceof Array)
    {
      var rgOut = [];
      var k = obj.length;
      for (var i=0; i<k; i++)
      {
        var el = obj[i];
        if (el===undefined)
           continue;
        var val = Recurse(el);
        rgOut.push(val);
      }
      return strLBr + rgOut.join(strComma) + strRBr;
    }
    else if (obj instanceof Object)
    {
      var rgOut = [];
      for (var i in obj)
      {
        var objField = obj[i];
        if (objField!=null && objField!=strEmpty)
        {
          var val = Recurse(objField);
          rgOut.push(EscapeString(i) + strColon + val);
        }
      }
      return strLCr + rgOut.join(strComma) + strRCr;
    }
    else //value
      return EscapeString(obj.toString());
  }
  var str = Recurse(obj);
  return str;
}

function DeSerializeJSON7(str)
{
  if (str==null)
    return null;
  var rxQStrings = new RegExp("'([^'\\\\]|\\\\.)*'", 'g');
  var rxInalidChars = new RegExp('[^{}\\[\\],: \\t\\n\\r]');
  var strTest = str.replace(rxQStrings,'');
  if (rxInalidChars.test(strTest))
    return null;
  var objResult = eval('('+str+')');
  return objResult;
}

function $(element) 
{
    return (typeof element == 'string') ? document.getElementById(element) : element;
}

function getCookie(cookiename)
{
    if (cookiename == null || cookiename === '') 
        return '';
    var cookiestring = ''+document.cookie;
    var index1 = cookiestring.indexOf(cookiename + '=');
    if (index1 == -1) 
        return '';
    var index2 = cookiestring.indexOf(';',index1);
    if (index2 == -1) 
        index2 = cookiestring.length;
    return unescape(cookiestring.substring(index1+cookiename.length+1, index2));
}

function StrGetCookie(strName)
{
    var strNameEQ = strName + "=";
    var rgCookies = document.cookie.split(';');
    for(var i in rgCookies)
    {
      var strCookie = rgCookies[i];
      var strCookie2 = ltrim (strCookie);
        if (strCookie2.indexOf(strNameEQ) == 0)
        {
          var strResult = strCookie2.substring(strNameEQ.length, strCookie2.length);
          if (strResult=='')
            strResult = null;
          if (strResult!=null)
            strResult = decodeURIComponent(strResult);
          return strResult;
        }
    }
    return null;
}

function CreateCookie(strName, strValue, secondsTimeToLive)
{
    var dtExpiration = new Date();
    dtExpiration.setTime(dtExpiration.getTime()+secondsTimeToLive*1000);
    var strExpires = dtExpiration.toGMTString();
    var strEncodedValue = strValue==null ? null : encodeURIComponent(strValue);
    var strC = strName + "=" + strEncodedValue + ";expires=" + strExpires + ";path=/ ";
    document.cookie = strC;
}

function DeleteCookie(strName)
{
  CreateCookie(strName, "", -1);
}

//
// Pasrses _form cookie and fills appropriate elements using IDs
//
function parseFormCookie()
{
    var form = getCookie('_form').split(';');
    var e;
    var c;
    var v;
    for (var i = 0; i < form.length; ++i)
    {
        c = form[i].split('=');
        if (c.length != 2)
            continue;
        e = document.getElementById(c[0]);
        if (e == null)
            continue;
        v = unescape(c[1]);
        if (e.tagName == 'INPUT')
        {
            if (e.type.toUpperCase() != 'CHECKBOX')
            {
                e.value = v;
            }
            else
            {
                e.checked = v == 'true';
            }
        }
        else
        {
            SetInnerText(e, v);
        }
    }
    DeleteCookie('_form');
    
    e = document.getElementById(getCookie('_formFocus'));
    if (e != null)
    {
        DeleteCookie('_formFocus');
        focusElement(e, true);
        return true;
    }
    else
    {
        return false;
    }
}

//
// M7Dialog class
//
var g_activeDialog = null;

function removeActiveDialog()
{
    var hnodeDialogBackground = document.getElementById('ID_ModalDialogBackground');
    hnodeDialogBackground.style.display = 'none';
    
    if (g_activeDialog!=null)
    {
        var hnodeDialog = g_activeDialog.dialogHnode;
        hnodeDialog.parentNode.removeChild(hnodeDialog);
    }
    g_activeDialog = null;
}

function collectElements(parent, all)
{
    var tag;
    for(var e = parent.firstChild; e != null; e = e.nextSibling)
    {
        if (e.nodeType != 1) continue;
        e.allIndex = all.push(e) - 1;
        tag = e.tagName;
        e.focusable = tag === 'INPUT'  || tag === 'BUTTON' || tag === 'A' || tag === 'SELECT' || tag === 'TEXTAREA';
        collectElements(e, all);
    }    
}

function dialogKeydownHandler(event, dialog)
{
    var src = event.srcElement ? event.srcElement : event.target;
    
    if (!src) return true;

    //process Esc
    if (event.keyCode == 27)
    {
        dialog.cancelAction();
        return false;
    }
    
    //process Enter
    if (event.keyCode == 13)
    {
        // ignore Enter for buttons, links, input submit or elements with default action
        var tag = src.tagName;
        var srcType = src.type ? src.type.toUpperCase() : null;
        if ( tag === 'BUTTON' || tag === 'A' || 
            (tag === 'INPUT' && (srcType === 'SUBMIT' || srcType === 'RESET' || srcType === 'BUTTON' || srcType === 'FILE' || srcType === 'IMAGE')) || 
            src.defaultAction)
        {
            return true;
        }
        
        // if textarea, ctrl+enter will save and regular enter will simply pass thru. in other areas, any enter will save
        if (tag !== "TEXTAREA" || event.ctrlKey)
        {
            dialog.okAction();
            return false;
        }
        else
        {
            return true;
        }
    }
    
    //process Tab
    if (event.keyCode == 9) 
    {    
        var elements = dialog.allElements;
        if (elements.length == 0) return true;
        
        var srcIndex = src.allIndex;
        var i = srcIndex;
        
        var forward=!event.shiftKey;
        
        //forward
        for(;;)
        {
            if (forward)
            {
                ++i;
                if (i >= elements.length) i = 0;
            }
            else
            {
                if (i == 0) i = elements.length;
                --i;
            }
            if (i == srcIndex) return true;
            
            var e = elements[i];
            if (e.focusable && e.scrollWidth != 0 && e.scrollHeight != 0)
            {
                if (focusElement(e)) 
                {
                    event.cancelBubble = true;
                    if (event.stopPropagation) event.stopPropagation();
                    if (event.preventDefault) event.preventDefault();
                    return false;
                }
            }
        }
    }
    return true;
}

// render binds focus event handlers for dialog (to prevent tab focus escape)
// call render if you change DOM of already shown dialog (show calls render before displaying)
M7Dialog.prototype.render = function ()
{
    this.allElements = [];
    collectElements(this.dialogHnode, this.allElements);
    
    var dialog = this;
    if (this.dialogHnode.addEventListener)
    {
        this.dialogHnode.addEventListener('keydown', function(event) { return dialogKeydownHandler(event, dialog); }, true);
    }
    else
    {    
        this.dialogHnode.onkeydown = function() { return dialogKeydownHandler(event, dialog); };
    }
}

M7Dialog.prototype.focusDefault = function()
{
    if (this.allElements)
    {
        var first = null;
        var e;
        for(var i = 0; i < this.allElements.length; ++i)
        {
            e = this.allElements[i];
            
            if (e.dialogDefaultElement || e.className.match('dialogDefaultElement') != null)
            {
                focusElement(e,true);
                return;
            }
            
            if (e.focusable && first == null) first = e;
        }
        
        if (first != null)
        {
            focusElement(first,true);
            return;
        }
    }
    
    focusElement(this.dialogHnode.firstChild,true);
}

M7Dialog.prototype.show = function(anchor, fNoDocShading)
{
    if (g_activeDialog != null)
    {
        assert(false);
        removeActiveDialog();
    }

    var hnodeDialogBackground = document.getElementById('ID_ModalDialogBackground');
    if ( fNoDocShading )
    {
        hnodeDialogBackground.style.filter = 'alpha(opacity=0)';
        hnodeDialogBackground.style.opacity = '0';
    }
    else
    {
        hnodeDialogBackground.style.filter = 'alpha(opacity=50)';
        hnodeDialogBackground.style.opacity = '0.50';
    }
    hnodeDialogBackground.style.display = '';
    SizeDialogBackground();

    this.anchorElement = $(anchor);
    var hnodeDialog = this.dialogHnode;
    hnodeDialog.style.zIndex=100;
    hnodeDialog.style.top = this.anchorElement.offsetHeight + 'px';

    this.render();
    
    this.anchorElement.insertBefore(hnodeDialog, null);
    
    this.focusDefault();

    g_activeDialog = this;
}

M7Dialog.prototype.close = function()
{
    removeActiveDialog();
}

M7Dialog.prototype.onOk = function()
{
    return true;
}

M7Dialog.prototype.onCancel = function()
{
    return true;
}

// @TODO: wire onOuterClick
M7Dialog.prototype.onOuterClick = function()
{
    if (this.closeOnOuterClick)
    {
        this.cancelAction();
    }
    else
    {
        this.focusDefault();
    }
}

M7Dialog.prototype.okAction = function()
{
    if (this.onOk())
    {
        this.close();
    }
}

M7Dialog.prototype.cancelAction = function()
{
    if (this.onCancel())
    {
        this.close();
    }
}

M7Dialog.prototype.addButtonEx = function(buttonName, customAction)
{
    this.ID_DialogButtonTr.style.display = '';
    
    var button = document.createElement('button');
    button.className = 'dialogButton';
    SetInnerText(button, buttonName);
    button.onclick = customAction;
    
    this.ID_DialogButtonTd.appendChild(button);
    return button;
}

//
// closes dialog if action returns true
//
M7Dialog.prototype.addButton = function(buttonName, action)
{
    var dialog = this;
    return this.addButtonEx( 
        buttonName, 
        function() { if (action()) { dialog.close(); } } 
        );
}

//
// closes dialog if action returns true
//
M7Dialog.prototype.addOkButton = function(buttonName)
{
    var dialog = this;
    return this.addButtonEx( 
        buttonName ? buttonName : '   OK   ', 
        function() { dialog.okAction(); } 
        );
}

//
// closes dialog if action returns true
//
M7Dialog.prototype.addCancelButton = function(buttonName)
{
    var dialog = this;
    return this.addButtonEx( 
        buttonName ? buttonName : 'Cancel', 
        function() { dialog.cancelAction(); } 
        );
}

function M7Dialog(body, title, noCloseButton, closeOnOuterClick)
{
    var dialog = this;
    
    this.anchorElement = null;
    this.closeOnOuterClick = closeOnOuterClick;
    
    this.dialogHnode = document.getElementById('ID_DialogFrame').cloneNode(true);
    RememberIDs(this.dialogHnode, this, false);
    
    if (title == null && noCloseButton)
    {
        this.ID_DialogTitleBar.style.display = 'none';
    }
    else
    {
        if (title != null)
        {
            SetInnerText(this.ID_DialogTitleText, title);
        }
        if (noCloseButton)
        {
            this.ID_DialogCloseButtonTd.style.display = 'none';
        }
        else
        {
            this.ID_DialogCloseButtonA.onclick = function() { dialog.cancelAction(); return false; };
        }
    }
    
    this.dialogBody = $(body).cloneNode(true);
    RememberIDs(this.dialogBody, this, false);
    this.ID_DialogBodyParent.appendChild(this.dialogBody);
}
