//------------------------
// ajax wrapper functions
//------------------------
// XML returns (or passes to CallBackFunc) a parsed XMLDOM object
// GetRequest returns (or passes to CallBackFunc) response as a string: raw JScode, Text, HTML, or unparsed XML
// To make an Asyncronous call, pass in a valid CallBackFunc (optional)
// To use cached responses, pass in bUseCache = true (optional)
//------------------------
function GetRequest    (url, bUseCache,   CallBackFunc ){ return GetReq( url, bUseCache, CallBackFunc, false, null ); }
function GetRequestXML (url, bUseCache,   CallBackFunc ){ return GetReq( url, bUseCache, CallBackFunc, true,  null );  }
function PostRequest   (url, postDataStr, CallBackFunc ){ return GetReq( url, null,      CallBackFunc, false, postDataStr ); }
function PostRequestXML(url, postDataStr, CallBackFunc ){ return GetReq( url, null,      CallBackFunc, true,  postDataStr );  }
function ImportScript  (jsurl, bUseCache, CallBackFunc) { return _ImportScript(jsurl, bUseCache, CallBackFunc);}
function ImportStyle   (cssurl, bUseCache, CallBackFunc){ return _ImportStyle(cssurl, bUseCache, CallBackFunc); };
function GetJSObject   (jsurl){ return _GetJSObject(jsurl); }
function GetJSObjectPOST(jsurl,postdata){ return _GetJSObject(jsurl,postdata); }
function CreateStyleTag(str)  { return _CreateStyleTag(str); }
//------------------------
// Syncronous JS loading usage:  eval(GetRequest(jsscripturl);
// Asyncronous JS loading usage: eval(GetRequest(jsscripturl, false, myCallBack);
//------------------------
//Use this "base" object to create and load a single self-contained dynamic objects (syncronous)
function _GetJSObject(jsurl){
  //example code to be eval'd:  this.value1 = x; this.value2 = y; (only the innards of the object)
  // Usage: 
  // var obj = new GetJSObject(jsurl); //create and load a dynamic js object
  // obj.reload(optionalUrl); //reload with current data
  // alert(obj.value1); //do something with it
  this.url = jsurl;
  this.reload = function(newurl){
    this.url = ((newurl)?newurl:this.url);
    eval(GetRequest(this.url));
    return this;
  }
  return this.reload();
}
function _GetJSObjectPOST(jsurl,postdata){ //POST version of above
  this.url = jsurl;
  this.post = postdata;
  this.reload = function(newurl){
    this.url = ((newurl)?newurl:this.url);
    eval(GetRequest(this.url,false,null,false,this.post));
    return this;
  }
  return this.reload();
}
function _GetJSObjectASync(jsurl,callback,postdata){
  this.url = jsurl;
  this.post = postdata;
  this.reload = function(newurl){
    this.url = ((newurl)?newurl:this.url);
    GetRequest(this.url,false,this.cb,false,this.post);
    return this;
  }
  this.cb = function(s){
    eval(s);
    return this;
  }
  return this.reload();
}
//------------------------
// Cross-Domain Asynconsous JS script loading function (loaded script is executed in window.scope)
function _ImportScript(jsurl, bUseCache, CallBackFunc, SafariTest )
{
  //Supply CallBack to verify load before accessing loaded objects.  
  //Use SafariTest to trigger the callback func for safari, e.g. test for vars defined in the loaded script
  var head = document.getElementsByTagName('head').item(0);
  var s = document.createElement("SCRIPT");
  s.src = ((bUseCache)?jsurl:GetUniqueURL(jsurl));
  s.type = "text/javascript";
  if(typeof CallBackFunc == "function"){
    if(typeof s.onreadystatechange != "undefined"){//ie
      s.onreadystatechange = function(){if(/loaded|complete/.test(s.readyState)){s.onreadystatechange = null; CallBackFunc();} };
    }else if(/safari/i.test(navigator.userAgent) && SafariTest ){ //Safari does not support event callbacks - use timer callbacks test for defined conditions
      window.SafariLoaded = function(){if(eval(SafariTest)){ CallBackFunc(); }else{ window.setTimeout("window.SafariLoaded()",100)}; }
      window.SafariLoaded();
    }else{
      CallBackFunc.once = true;//avoid repeated callbacks
      addEvent(     s, "load", function(){ if(CallBackFunc.once){CallBackFunc.once = false; CallBackFunc();} } ); //mac:camino,moz,fx. win:moz,fx,opera 9x
      addEvent(window, "load", function(){ if(CallBackFunc.once){CallBackFunc.once = false; CallBackFunc();} } ); //opera 8x
    }
  }
  head.appendChild(s);
}
//------------------------
// Cross-Domain Asynconsous CSS StyleSheet loading function (auto-loaded into top level <head> scope)
function _ImportStyle(jsurl, bUseCache, CallBackFunc)
{
  // Supply CallBack to verify load before accessing loaded objects
  var head = document.getElementsByTagName('head').item(0);
  var s = document.createElement("LINK");
  s.rel = "stylesheet";
  s.href = ((bUseCache)?jsurl:GetUniqueURL(jsurl));
  s.type = "text/css";
  if(navigator.userAgent.match(/opera/i)) 
    addEvent(window, "load", CallBackFunc );//opera
  else{
    addEvent(s, "load", CallBackFunc ); //moz
    s.onreadystatechange = function(){if(s.readyState=="loaded") CallBackFunc();}; //ie
  }
  head.appendChild(s);
}
//------------------------
// Dynamic <TAG>String<TAG> functions
function CreateStyleTag( str, win )//create, parse, execute a new <style></style> tag
{
  var d = GetDoc(win);
  var s = d.createElement('style');
  s.setAttribute('type', 'text/css');
  if(s.styleSheet)   { s.styleSheet.cssText = str; }//IE
  else{ s.appendChild( d.createTextNode(str) ); }//the world
  (d.getElementsByTagName('head')[0] ).appendChild(s);
}
function CreateScriptTag( str, win )//create, parse, execute a new <script></script> tag
{
  var d = GetDoc(win);
  var s = d.createElement('script');
  s.setAttribute('type', 'text/javascript');
  if(s.text)   { s.text = str; }//IE
  else{ s.appendChild( d.createTextNode(str) ); }//the world
  (d.getElementsByTagName('head')[0] ).appendChild(s);
}
function GetDoc(win){ return (win&&win.document)? win.document : window.document; }

//Scoping example - eval AJAX JS into window scope, instead of function scope
/*
function GetAjaxStuffIntoWindowScope(url){
  function EvalInWindowScope(str){
    CreateScriptTag( str );
  }
  GetRequest(url,false,EvalInWindowScope);
}
*/


//GetReq( "/pns/start.htp", false, function(s){alert(s);}, false, "username=bmckinney&password=lois"  )

//------------------------
//core functions
//------------------------
function GetReq( url, bCache, CallBackFunc, bXML, postData  )
{
  try{
    var bAsync = (typeof CallBackFunc=="function");
    var objSrvHTTP;
    objSrvHTTP = getXMLHTTPpool();
    if( objSrvHTTP ){
      if( typeof postData =="string"){ //Post the data
        objSrvHTTP.open("POST", url, bAsync);
        objSrvHTTP.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      }
      else if(!bCache){ //never use from cache
        try{
        objSrvHTTP.open("GET", ""+GetUniqueURL(url), bAsync);
        objSrvHTTP.setRequestHeader("Cache-Control","no-cache");
         objSrvHTTP.setRequestHeader("Pragma","no-cache");
         }catch(e){}
      }else{            //use from cache
        objSrvHTTP.open("GET", url, bAsync);
      }
      if( bAsync ){//asynchronous, use callback function for return
        objSrvHTTP.onreadystatechange = function(){
          if( objSrvHTTP.readyState == 4){
	          try{//CR 4464
            	if(objSrvHTTP.status == "200"){	            
              	CallBackFunc( ((bXML)?(Str2XMLDOM(String(objSrvHTTP.responseText))):String(objSrvHTTP.responseText)) );
            	}else{
              	CallBackFunc( null );
            	}
          	}catch(e){}
            objSrvHTTP.onreadystatechange = function(){};//null func
          }
        }
        objSrvHTTP.send( postData );
         return true;
      }else{       //syncronous (blocking), send and wait here for return
        objSrvHTTP.send( postData );
        if(objSrvHTTP.status == "200")
          return ((bXML)?(Str2XMLDOM(String(objSrvHTTP.responseText))):String(objSrvHTTP.responseText));
        return false;
      }
    }
  }catch(e){ if(objSrvHTTP){objSrvHTTP.abort();} }
  return false;
}
//------------------------
function getXMLHTTP(){ //x-browser xmlhttp creator  
  if(window.XMLHttpRequest){
    try{
      return new XMLHttpRequest();
    }catch(e){}
  }
  if(window.ActiveXObject){
    try{
      return new ActiveXObject("Microsoft.XMLHTTP");
    }catch(e){}
  }
  return null;
}
//------------------------
function getXMLHTTPpool(){ //pool of reusable XMLHTTP objects
  try{
    if(typeof window.xmlhttpfactory =="undefined"){//create a new global static object pool
      window.xmlhttpfactory = new Array();
      return (window.xmlhttpfactory[0] = getXMLHTTP());
    }
    else{ //get from pool
      for(var i=0; i < window.xmlhttpfactory.length; i++){
        if ( window.xmlhttpfactory[i].readyState == 4 || window.xmlhttpfactory[i].readyState == 0 ){
          return window.xmlhttpfactory[i];
        }
      }//else none available, create another one, add to pool
      return (window.xmlhttpfactory[window.xmlhttpfactory.length] = getXMLHTTP());    
    }
  }catch(e){return null;}
}
//------------------------
function Str2XMLDOM(s){ //x-browser XML factory: create parsed XMLDOMobj from string
  try{
    if(typeof ActiveXObject!="undefined"&&typeof GetObject!="undefined"){
      var b=new ActiveXObject("Microsoft.XMLDOM");
      b.loadXML(s);
      return b;
    }else if(typeof DOMParser!="undefined"){
      return (new DOMParser()).parseFromString(s,"text/xml");
    }else{
      return null;
    }
  }catch(e){return null;}
}
//------------------------
function GetUniqueURL(s){ //append unique GET query nvpair to help prevent browser cache
  s += "";
  return s + ((s.match(/\?/))?"&":"?") + (new Date()).valueOf()+"guu="+(new Date()).valueOf();
}

//------------------------
// Use these wrappers to Fix DOM-JS memory leak in IE
//------------------------
// http://www.crockford.com/javascript/memory/leak.html
// The purge function should be called before removing any element 
// either by the removeChild method, or by setting the innerHTML property.
function LLremoveChild(par,child){ purge(child); par.removeChild(child); }
function LLinnerHTML(e, html){ purge(e); e.innerHTML = html; }
function purge(d) {
  var a = d.attributes, i, l, n;
  if (a) {
    l = a.length;
    for (i = 0; i < l; i += 1) {
      n = a[i].name;
      if (typeof d[n] == 'function') {
        d[n] = null;
      }
    }
  }
  a = d.childNodes;
  if (a) {
    l = a.length;
    for (i = 0; i < l; i += 1) {
      purge(d.childNodes[i]);
    }
  }
}
