﻿var Lib=
{
    Browser:
    {
        // Returns a string containing the value of a parameter from the url
        // If not found, boolean false is returned.
        GetUrlArg:function(sKey,sPseudoHref)
        {
            var s=sPseudoHref?sPseudoHref:Local.testUrl?Local.testUrl:document.location.href;
            
            if(s.indexOf("?")==-1)
                return false;
            for(var i=0,c=s.split("?")[1].split("&");i<c.length;i++)
                if(c[i].split("=")[0].toLowerCase()==sKey.toLowerCase())
                    return c[i].split("=")[1].toString();
            return false;
        },
        // The browser detection functions below should be improved upon
        // Also add detection for version numbers and for Opera and other clients
        isIE:function()
        {
            return navigator.userAgent.toLowerCase().indexOf("msie")>-1?true:false;
        },
        isMOZ:function()
        {
            return navigator.userAgent.toLowerCase().indexOf("gecko")>-1?true:false;
        },
        isMAC:function()
        {
			return navigator.userAgent.toLowerCase().indexOf("macintosh")>-1?true:false;
        },
        isOpera:function()
        {
            return false;
        }
    },
    String:
    {
        Truncate:function(sInput,sEnd,iMaxChars)
        {
            if(sInput.length>iMaxChars)
                return sInput.substr(0,iMaxChars-sEnd.length)+sEnd;
            else 
                return sInput;
        },
        // TODO: Implement. Code below doesn't work..
        Trim:function(sInput)
        {
            return sInput.replace(/\s/ig,"");
            //return sInput.replace(/(\s*)[^\s]/ig,"")
        }
    },
    Html:
    {
		// returns the position of the element in relation to the top left corner
		// only works for IE and possibly mozilla browsers
        grp:function(eEl)
        {
            for(var x=eEl.offsetLeft,y=eEl.offsetTop;eEl.offsetParent;x+=eEl.offsetLeft,y+=eEl.offsetTop)
                eEl=eEl.offsetParent;
            return {x:x,y:y};
        },
        grpWscroll:function(eEl)
        {
            for(var x=eEl.offsetLeft,y=eEl.offsetTop;eEl.offsetParent;x+=eEl.offsetLeft,y+=eEl.offsetTop)
            {
                eEl=eEl.offsetParent;
                x-=eEl.scrollLeft;
                y-=eEl.scrollTop;
            }
            return {x:x,y:y};
        },
        // incomplete
        traverse:function(eEl)
        {
			var s="Node Ancestors:\n------------\n";
			for(var c=eEl;c.parentNode;c=c.parentNode)
				s+=Lib.Html.GetSimpleData(c)+"\n";
			s+="------------\nChildNode count: "+eEl.childNodes.length+"\n";
			for(var i in eEl)
			{
				if(i.toString().substr(0,2).toLowerCase()=="on")
					if(eEl[i])
						s+=i+" = "+eEl[i];
			}
			return s;
        },
        // returns a short string representing the tagname, id and classes of the element
        GetSimpleData:function(eEl)
        {
			var s="";
			s+=eEl.tagName+" ";
			s+=eEl.id?("#"+eEl.id+" "):"";
			s+=eEl.className?"."+eEl.className:"";
			return s;
        },
        // TODO: Implement multiple classes in call. E.g. "class1 class2" for excluding and "class1/class2" for including.
       getElementsByClassName:function(sClassName,oParentNode, oTagName)
       {
            var first = true;
            if (oTagName == null)
            {
              oTagName = "*";
            }
            if (oTagName == "")
            {
              oTagName = "*";
            }
            if (first) {
              sClassName=sClassName.toLowerCase();
              oParentNode=oParentNode?oParentNode:document;
              
              var r=[];
              var c=oParentNode.getElementsByTagName(oTagName);
              for(var i=0;i<c.length;i++)
              {
                  var classes = c[i].className.split(" ");
                  for(var j=0;j<classes.length;j++)
                      if(classes[j].toLowerCase()==sClassName)
                      {
                          r[r.length]=c[i];
                          break;
                      }
              }
              return r;
            } else {
                oParentNode=oParentNode?oParentNode:document;
                var strTagName = oTagName;
                var arrElements = (strTagName == "*" && oParentNode.all)? oParentNode.all : oParentNode.getElementsByTagName(strTagName);
                var arrReturnElements = new Array();
                sClassName = sClassName.replace(/\-/g, "\\-");
                var oRegExp = new RegExp("(^|\\s)" + sClassName + "(\\s|$)");
                var oElement;
                for(var i=0; i<arrElements.length; i++){
                  oElement = arrElements[i];
                  if(oRegExp.test(oElement.className)){
                    arrReturnElements.push(oElement);
                  }
                }
                return (arrReturnElements)

            }
        },
        isHtmlElement:function(el)
        {
            if(el&&el.tagName&&el.tagName!="!"&&typeof(el.innerHTML)=="string")
                return true;
            return false;
        }
    },
    XmlHttp:
    {
		channels:[],
		Load:function(sUrl,fCb,bAllowCachedResponse,returnResponseObject)
		{
		    if(!bAllowCachedResponse)
				sUrl+=(sUrl.indexOf("?")>-1?"&":"?")+"uid="+Math.random();
			var xmlhttp;
			if(window.XMLHttpRequest)
				xmlhttp = new XMLHttpRequest();
			else if(window.ActiveXObject)
				//xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		    
			xmlhttp.onreadystatechange=new Function("","Lib.XmlHttp.readystatechange("+this.channels.length+")");
			
			this.channels[this.channels.length]={obj:xmlhttp,cb:fCb,fullReturn:returnResponseObject?true:false};
			
			xmlhttp.open("GET",sUrl,true);
			xmlhttp.send(null);
		},
		readystatechange:function(iChannelIndex)
		{
			var xmlhttp = this.channels[iChannelIndex].obj;
			
			var c=this.channels[iChannelIndex];
			if(xmlhttp&&xmlhttp.readyState==4)
				c.cb(c.fullReturn?xmlhttp:xmlhttp.responseText);
		}
    },
    Event:
    {
		attachEvent:function(oObj,sEventName,fEventHandler)
		{
			if(sEventName.toLowerCase().indexOf("on")==0)
				sEventName = sEventName.substr(2);
			if(oObj.attachEvent)
				oObj.attachEvent("on"+sEventName,fEventHandler);
			else if(oObj.addEventListener)
				oObj.addEventListener(sEventName,fEventHandler,true);
		}
    },
    Debug:
    {
        TurnOn:function()
        {
            window.ao=function(o)
            {
                var s="";
                for(var i in o)
                    s+=i+" = "+o[i]+"\n";
                alert(s);
            }
            var el=this.element=document.createElement("INPUT");
            el.type="text"
            el.style.position="absolute";
            el.style.top="0px";
            el.style.left="0px";
            el.style.width="200px";
            document.body.appendChild(el);
            el.onkeydown=function(e){Lib.Debug.keydown(e)};
            el.focus();
        },
        keydown:function(e)
        {
            if(!e&&event)
                e=event;
            if(e.keyCode==13&&e.shiftKey)
                alert(eval(this.element.value));
            else if(e.keyCode==13)
                eval(this.element.value);
        },
        ShowCallStack:function(f, s)
        {
            if(typeof(s)!="string")
                s="";
            if(f.caller)
            {
                s+=this.getFunctionName(f.caller);
                s+="("+this.getFunctionArgs(f.caller)+")";
                s+="\n";
                return this.ShowCallStack(f.caller,s);
            }
            alert(s);
            return s;
        },
        getFunctionName:function(oFunction)
        {
            var s=Lib.String.Trim(oFunction.toString().substr(0,oFunction.toString().indexOf("{")));
            //s+=" "+oFunction.object+" ";
            /* Build reference tree of objects and attached methods.
            e.g. (A)traverse all types "object" on window.
            (B)traverse function in every (A)
            For every step add object reference to excludedlist to prevent circular references.
            Use the completed list to establish context with the function argument and extract the methodName.
            Notify if multiple functions with differing names and identical method bodies were found.
            */
           return s;
            s=s.replace("function","");
            if(s.split("(")[0]=="")
                s="[anonymous function]("+s.split("(")[1];
            return s;
        },
        getFunctionArgs:function(oFunction)
        {
            var r="";
            for(var i=0;i<oFunction.arguments.length;i++)
                r+=(i>0?",":"")+this.getSimpleType(oFunction.arguments[i])
            return r;
        },
        getSimpleType:function(oThing)
        {
            return typeof(oThing)
        }
    }
}
