//Standard JS communication functions
//Author: Allan Betschart
//////////////////////////////////////////////////////////////////
var doc=document;
var proto= location.protocol ? location.protocol + "//" : "http://";
var host = location.hostname ? location.hostname : "ibop2";
var port= location.port ? ":"+location.port : "";
var baseUrl=proto+host+port+location.pathname;
baseUrl=baseUrl.replace("index.php","");
var mainUrl=proto+host+port+"/tick_xml/data.xml";
mainUrl=baseUrl+"php/actions.php";      //Bridge PHP until a real server is made
if (/individuals/.test(baseUrl))
//if (/test/.test(baseUrl))
{mainUrl=proto+"individuals.interactivebrokers.com/webtms/ibslb/php/actions.php";}
//{mainUrl="php/actions.php";}
else
{mainUrl=proto+"www.interactivebrokers.com/webtms/ibslb/php/actions.php";}      //Bridge PHP until a real server is made
//mainUrl="php/actions.php";
var Xmethod="GET";
var GET = "GET";
var POST = "POST";
var MaxRetry=3;
var findNode;
var isOpera=(/opera/.test(navigator.userAgent.toLowerCase()));
var isSafari=(/safari/.test(navigator.userAgent.toLowerCase()));
var isMac=(/mac/.test(navigator.userAgent.toLowerCase()));
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////Check compatibility////////////////////////////////////////
function checkJS()//Even though browser is maybe supported,
{                 //check needed JS for basic functions
  if (!document.getElementById)
    {return false;}
  if ((!window.ActiveXObject)&&(!window.XMLHttpRequest))
    {return false;}
  if (window.ActiveXObject)
  {
    try
    {
      new ActiveXObject("Microsoft.XMLHTTP")
      new ActiveXObject("MSXML2.DOMDocument");
    }
    catch(e)
      {return false;}
  }
  if ((!window.ActiveXObject)&&(!document.implementation)&&(document.implementation.createDocument))
    {return false;}
  return true
}
/////////////////////////////////////////////////Add XML attr to Moz//////////////////////////////////
if (window.Node && Node.prototype)
{
  try
    {Node.prototype.__defineGetter__("xml",XML2str);}
  catch(e)
  {
    try{Node.prototype.xml=null;}
    catch(c){}
  }
}
function XML2str() 
{
  var Xser = new XMLSerializer();
  return Xser.serializeToString(this);
}
function X2S(node)
{
  var Xser = new XMLSerializer();
  return Xser.serializeToString(node);
}
/////////////////////////////////////////////////New XML Doc//////////////////////////////////////////
function newDoc(rootName,xmlFile)
{
  var isStr = 0;
  if (/^\<\?xml/.test(xmlFile))
    {isStr = 1;}
  if (rootName == null)
    {rootName="root";}
  var xmlDoc;
  if (window.ActiveXObject)
  {
    xmlDoc = new ActiveXObject("MSXML2.DOMDocument");
    if (xmlFile == null)
    {
      xmlDoc.loadXML('<?xml version="1.0" encoding="UTF-8"?>');
      var root = xmlDoc.createElement(rootName);
      xmlDoc.appendChild(root);
    }
    else
    {
      xmlDoc.async="false";
      if (isStr != 0)
      {
        xmlDoc.loadXML(xmlFile);
        return xmlDoc;
      }
    }
  }
  else
  {
    if (isStr == 0)
    {
      if (xmlFile == null)
      {
        xmlDoc=document.implementation.createDocument('',rootName,null);
        if (xmlDoc.documentElement == null)
        {
          var root = xmlDoc.createElement(rootName);
          xmlDoc.appendChild(root);
        }
      }
      else
        {xmlDoc=document.implementation.createDocument('','',null);}
    }
    else
    {
      xmlDoc = new DOMParser();
      return xmlDoc.parseFromString(xmlFile,"text/xml");
    }
  }
  if ((xmlDoc)&&(xmlFile != null))
    {xmlDoc.load(xmlFile);}
  else
  {
      var pi = xmlDoc.createProcessingInstruction("xml", "version='1.0' encoding='UTF-8'"); 
      var root = xmlDoc.documentElement;
      xmlDoc.insertBefore(pi, root); 
  }
  return xmlDoc;
}
/////////////////////////////////////////////////XML 2 HTML via XSL///////////////////////////////////
function xslt(xmlDoc,xslDoc) 
{
  try
  {
    if (window.ActiveXObject) 
      {return xmlDoc.transformNode(xslDoc);}
    else 
    {
      var xsl = new XSLTProcessor();
      xsl.importStylesheet(xslDoc);
      var fragment=xsl.transformToFragment(xmlDoc, document);
      if( fragment.childNodes.length > 0 )
        {return fragment.childNodes[0].innerHTML;}
      else
        {return;}
    }
  }
  catch(e){return;}
}
/////////////////////////////////////////////////Node transcode///////////////////////////////////////
function transNode(targetNode,srcNode,xslDoc)
{
  var xmlDoc=newDoc("root");
  var root = xmlDoc.documentElement;
  root.appendChild(srcNode);
  targetNode.innerHTML=xslt(xmlDoc,xslDoc);
}
/////////////////////////////////////////////////Class to send Builder////////////////////////////////
function newClass(className)
{
  var xmlDoc=newDoc("root",null);
  var root = xmlDoc.documentElement;
  var cls=xmlDoc.createElement("class");
  root.appendChild(cls);
  cls.setAttribute("name",className);
  var params=xmlDoc.createElement("params");
  cls.appendChild(params);
  this.insertParam=function(type,val){return new _insertParam(type,val,params);};
  this.insertMethod=function(methName)
                    {
                      var meth=xmlDoc.createElement("method");
                      cls.appendChild(meth);
                      meth.setAttribute("name",methName);
                      var params=xmlDoc.createElement("params");
                      meth.appendChild(params);
                      this.insertParam=function(type,val){return new _insertParam(type,val,params);};
                      this.hasChildNodes=function(){return meth.hasChildNodes();}
                    }
  function _insertParam(type,val,pNode)
  {
    var param=xmlDoc.createElement("param");
    pNode.appendChild(param);
    if (type != null)
      {param.setAttribute("type",type);}
    if (val != null)
    {
      var TN=xmlDoc.createTextNode(val);
      param.appendChild(TN);
    }
    this.insertParam=function(type,val){return new _insertParam(type,val,param);};
    this.hasChildNodes=function(){return param.hasChildNodes();}
  }
  this.xmlDoc=xmlDoc;
  this.toXMLstr=function(){return xmlDoc.xml};
}
/////////////////////////////////////////////////XMLHTTP parser///////////////////////////////////////ä
function ParseXMLstr(xmlStr)
{
  var xmlDoc=newDoc(null,xmlStr);
  ParseXML(xmlDoc);
}
function ParseXML(xmlDoc)
{
  if (xmlDoc.getElementsByTagName('Exception').length)
  {
    alert("Uho, something went wrong.\nIf you remember what you did,\nemail help@interactivebrokers.com with the details");
    return;
  }
  for (var c=0; c < xmlDoc.getElementsByTagName('class').length; c++)
  {
    var clsNode = xmlDoc.getElementsByTagName('class')[c];
    var cls = clsNode.getAttribute("name");
    var clsArr=cls.split(/\./);
    cls=eval("new "+clsArr[0]+"()");
    var evalCls="cls.";
    for (var e = 1; e < clsArr.length; e++)
      {evalCls+=clsArr[e]+".";}
    for (var m=0; m < clsNode.getElementsByTagName('method').length; m++)
    {
      var currNode = clsNode.getElementsByTagName('method')[m];
      var method = currNode.getAttribute("name");
      eval(evalCls+method+"(currNode)");
    }
  }
}
function ParseXMLHTTP(xmlhttp,xmlDoc,url,method,XMLAlert_cnt)
{
  window.status=" ";
  if ((xmlhttp.readyState == 4)&&(xmlhttp.status == 200)&&
      (xmlhttp.responseText != null)&&(xmlhttp.responseText != ""))
  {//alert(xmlhttp.responseText);
//    try
//    {
      ParseXML(xmlhttp.responseXML);
//    }
//    catch(e)
//      {alert(e.message ? e.message : e);}
  }
  else if ((xmlhttp.readyState == 4)&&(xmlhttp.status == 200)&&
           ((xmlhttp.responseText == null)||(xmlhttp.responseText == "")))
    {XMLexchange(xmlDoc,url,method,XMLAlert_cnt);}
  else if ((xmlhttp.readyState == 4)&&(xmlhttp.status != null)&&(xmlhttp.status != 200))
  {
    if (XMLAlert_cnt < MaxRetry)
    {
      XMLAlert_cnt++;
      alert("An error occured while attempting data exchange\nRetry "+XMLAlert_cnt+" of "+MaxRetry);
      XMLexchange(xmlDoc,url,method,XMLAlert_cnt);
    }
    else
      {alert("Retry failed! Reason below\n"+xmlhttp.responseText);}
  }
}
/////////////////////////////////////////////////XMLHTTP loader///////////////////////////////////////
function XMLexchange(xmlDoc,url,method,XMLAlert_cnt)
{
  var date=new Date();
  var sysTime=date.getTime();
  if (XMLAlert_cnt == null)
    {XMLAlert_cnt=0;}
  var xml="";
  if (xmlDoc.xml != null)
    {xml=xmlDoc.xml;}
  else
    {xml=X2S(xmlDoc.firstChild.nextSibling);}
  xml=xml.replace(/[\r\n]/g,'');
  if (url == null)
    {url=mainUrl;}
  url+="?sys="+sysTime+"&sVer=1";//+sVer;
  if (method == null)
    {method=GET;}
  var xmlhttp;
  if (window.XMLHttpRequest)
    {xmlhttp=new XMLHttpRequest;}
  else if (window.ActiveXObject)
    {xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
  else
    {alert("No xmlHTTP");return;}
  if (xmlhttp)
  {
//alert(url);
    try
      {xmlhttp.open(method, url, true);}
    catch(e)
    {
      var err=e.message ? e.message : e;alert(err);
      //window.setTimeout(function(){XMLexchange(xmlDoc,url,method,XMLAlert_cnt);},500);
      return;
    }
    xmlhttp.onreadystatechange=function() {ParseXMLHTTP(xmlhttp,xmlDoc,url,method,XMLAlert_cnt);}
    xmlhttp.setRequestHeader("Content-Type","text/xml");
    xmlhttp.setRequestHeader("xml-data","<<>>"+xml+"<<>>");
    xmlhttp.send(null);
  }
}
/////////////////////////////////////////////////make xml entities into chars/////////////////////////
function XML2char(data)
{
  data=data.replace(/\&#(\d+)\;/g,function($1,$2){return String.fromCharCode($2)});
  data=data.replace(/\&nbsp\;/g," ");
  return data=data.replace(/<br\/>/g,"\n");
}
/////////////////////////////////////////////////make chars xml safe//////////////////////////////////
function char2XML(data)
{
  data=data.toString().replace(/([\"'&<>\u0000-\u001F\u007F-\uFFFF])/g,function($1){return ("&#"+$1.charCodeAt(0)+";")});
  data=data.replace(/([\r\n])/g,"<br/>");
  data=data.replace(/\s\s/g,"&#160;&#160;");
  return data;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////Push new page////////////////////////////////////////
function PushPage(page,windat,bool)
{
  if (!windat)
    windat="resizable,menubar=yes,toolbar=yes,scrollbars=yes";
  var date = new Date();
  time=date.getTime();
  var pushWin=window.open(page,(bool ? "win" : time) ,windat);
  return pushWin;
}
/////////////////////////////////////////////////get Cookie by name///////////////////////////////////
function getCookie(NAME)
{
  var cookie=document.cookie;
  if (!cookie)
    {return null;}
  var a=cookie.indexOf(NAME+"=")+NAME.length+1;
  var b=cookie.indexOf(";",a);
  if (b>=0)
    {return unescape(cookie.substring(a,b));}
  else
    {return unescape(cookie.substring(a));}
}
/////////////////////////////////////////////////set Cookie///////////////////////////////////////////
function setCookie(NAME,CookieSTR,expires)
{
  document.cookie=NAME+"="+escape(CookieSTR)+((expires == null) ? "" : 
                                              ("; expires="+expires.toGMTString()))+"; path=/";
}
/////////////////////////////////////////////////getElementBy custom class////////////////////////////
function getElementBy(custom)                                                        //class
{
  var customType = custom ? custom : "default";                                      //private variable
  function findByAttr(node,Attr,val)                                                 //private method
  {
    if ((node!=null)&&(node.hasChildNodes()))
    {
      var nodes = node.childNodes;
      for (var i=0; i < nodes.length; i++)  //first search childNode
      {
        try
        {
          if ((nodes[i][Attr] != null)&&(nodes[i][Attr] == val))
              {return nodes[i];}           //found a childNode with specified attribute and value
          if ((nodes[i].attributes != null)&&(nodes[i].attributes.length > 0))
          {
            var attr=nodes[i].getAttribute(Attr);
            if ((attr == null)&&(Attr == "className"))
              attr=nodes[i].getAttribute("class");
            if ((attr != null) && (attr == val))
              {return nodes[i];}            //found a childNode with specified attribute and value
          }
        }
        catch(e)
        {
          var err=e.message ? e.message : e;
          window.status=err;
        }
      }
      for (var i=0; i < nodes.length; i++)  //now search subNodes of childNodes
      {
        var subNode=findByAttr(nodes[i],Attr,val);
        if (subNode != null)
          {return subNode;}             //found a subNode of childNode with specified attribute and value
      }
    }
    else
      {return null;}                    //did not find any childNodes/subNodes with specified attribute and value
  }
  this.setCustomType=     function(str)     {customType=str;}                        //public method
  this.GetElementByName=  function(node,str){return findByAttr(node,"name",str);}    //public method
  this.GetElementById=    function(node,str){return findByAttr(node,"id",str);}      //public method
  this.GetElementByClass= function(node,str){return findByAttr(node,"className",str);}   //public method
  this.GetElementByCustom=function(node,str){return findByAttr(node,customType,str);}//public method
}
findNode=new getElementBy();
/////////////////////////////////////////////////insert node After referenceNode/////////////////////
function insertAfter(refNode, node)
{
  var pNode=refNode.parentNode;
  if (refNode.nextSibling)
    {pNode.insertBefore(node,refNode.nextSibling);}
  else
    {pNode.appendChild(node);}
}
/////////////////////////////////////////////////remove allchildren of node//////////////////////////
function removeChildren(node)
{
   while(node.hasChildNodes())
     {node.removeChild(node.firstChild);}
}
/////////////////////////////////////////////////find row of given table/////////////////////////////
function findRow(tableNode, id)
{
  var rows=tableNode.rows;
  for (var i=0; i < rows.length; i++)
  {
     if (findNode.GetElementById(rows[i],id) != null)
       {return i+1;}
  }
  return rows.length;
}
/////////////////////////////////////////////////Capitalize first letter of STR/////////////////////
String.prototype.ucFirst=function()
  {return this.substr(0,1).toUpperCase()+this.substr(1,this.length);}
/////////////////////////////////////////////////Toggle check boxes/////////////////////////////////
function toggleCheckAll(node,max,avoid)
{
  if (avoid == null)
    {avoid=Array();}
  var chk=node.checked;
  var nodeList=document.getElementsByName(node.name);
  var tot=((max)&&(nodeList.length > max)&&(chk)) ? max : nodeList.length;
  for (var i=0; i < tot; i++)
  {
    var skip = false;
    for(var v=0; v < avoid.length; v++)
    {
      if ((avoid[v].id == nodeList[i].id)&&(chk))
        {skip = true;}
    }
    if (!skip)
      {nodeList[i].checked=chk;}
  }
}
/////////////////////////////////////////////////Hook persistent Connection/////////////////////////
function hookPersistent()
{
  var date=new Date();
  var frm=document.createElement('iframe');
  frm.src="pusher.html?callback=parent.ParseXMLstr&t="+date.getTime();
  if (!(isSafari))
    {frm.style.display="none";}
  frm.style.height="0px";
  frm.style.width="0px";
  document.body.appendChild(frm);
}
////////////////////////////////////////////////Hash helper functions///////////////////////////////
Object.prototype.length=function()
                        {
                          var cnt="";
                          for (var k in this)
                          {
                            if (typeof(this[k]) == "function")
                              {continue;}
                            cnt+=k+" ";
                          }
                          return cnt;
                        };
Object.prototype.sort=function(reverse)//requires sorttable.js for Compare
                      {
                        var arr=new Array();
                        for (var k in this)
                        {
                          if (typeof(this[k]) == "function")
                            {continue;}
                          arr.push(k);
                        }
                        arr.sort(Compare);
                        if ((reverse != null)&&(reverse))
                          {arr.reverse();}
                        return arr;
                      };  
Object.prototype.keys=function()
                      {
                        var arr=new Array();
                        for (var k in this)
                        {
                          if (typeof(this[k]) == "function")
                            {continue;}
                          arr.push(k);
                        }
                        return arr;
                      };  
//////////////////////////////////replace callback support for safari///////////////////////////////
(function()
{
  var default_replace=String.prototype.replace;
  String.prototype.replace=function(search,replace)
                           {
                             //replace is not a function
                             if (typeof replace != "function")
                               {return default_replace.apply(this,arguments);}
                             var str="" + this;
                             var callback=replace;
                             //search string is not RegExp
                             if (!(search instanceof RegExp))
                             {
                               var idx=str.indexOf(search);
                               return (idx == -1 ? str : default_replace.apply(str,[search,callback(search,idx,str)]));
                             }
                             var reg=search;
                             var result=[];
                             var lastidx=reg.lastIndex;
                             var re;
                             while ((re = reg.exec(str)) != null)
                             {
                               var idx=re.index;
                               var args=re.concat(idx,str);
                               result.push(str.slice(lastidx,idx),callback.apply(null,args).toString());
                               if (!reg.global)
                               {
                                 lasyidx+=RegExp.lastMatch.length;
                                 break;
                               }
                               else
                                 {lastidx=reg.lastIndex;}
                             }
                             result.push(str.slice(lastidx));
                             return result.join("");
                           }
}
)();

