/********************************/
//	Dynamic Dependant Project
//	AJAX Stuff
//	Requires the foundation code
/********************************/

var ddp;
if(!ddp) ddp = {};
ddp.a = {};

/********************************/
//	DDP -> AJAX
/********************************/
(function() {

  /***************************************************************/
  //addHeaderScript
  //a.k.a. loadJSON (using only the first argument) exported to the ddp.a namespace as loadJSON as well.
  //add a script element to the document header using the supplied url
  //----arguments----
  //-strURL:    a url to a page to generate return data
  //-fnSuccess: callback function to recieve the returned data
  //-objWindow: optional. the window that the new script should be added to. (default is the current)
	function addHeaderScript(strURL, fnSuccess, objWindow){
    //if a browser window wasn't supplied, use the current one 
    objWindow = (typeof objWindow == 'object') ? objWindow : window;
    
    //we only need to add a function to the global scope if fnSuccess was passed 
    if(typeof fnSuccess == 'function'){
      //create a half time-based, half random-number string for the function name (e.g cbf125053068355207244769124226434)
      var strFunctionName = 'cbf' + new Date().getTime() + String(Math.random()).replace('.', '');
      //if the url already has a ? then add an &; otherwise, add a ?.
      strURL += (strURL.indexOf('?')+1) ? '&' : '?';
      //add a name value pair for passing the callback function name we generated.
      strURL += 'callback=' + strFunctionName;
      //create a global function with our function name 
      objWindow[strFunctionName] = function(){
        //pass all arguments to our success function
        fnSuccess.apply(objWindow, arguments);
        //once our function has executed, remove the global reference to the callback function name we generated.
        objWindow[strFunctionName] = undefined;
      };
    }
    //create a new script element
    var elNewScript = objWindow.document.createElement('script');
    elNewScript.type = 'text/javascript';
    elNewScript.src = strURL;
    //append the new script element to the <head> element
    objWindow.document.getElementsByTagName('head')[0].appendChild(elNewScript);
	}

  
  /***************************************************************/
  function request(url,destination){
    function successHandler(strData){
      if(typeof destination == 'object')
        destination.innerHTML = strData;
      else
        document.getElementById(destination).innerHTML = strData;
    }
    function failureHandler(intErrorNumber, strMessage){
      alert(intErrorNumber + ': ' + strMessage);
    }
    return HTTPRequest('get', url, null, successHandler, failureHandler);
  }

   
  /***************************************************************/
	function requestPost(url,params,callback){ //Uses POST and a Callback function (JSON response)
    return HTTPRequest('post', url, params, callback, function(intErrorNumber, strMessage){ alert(intErrorNumber + ': ' + strMessage); }, 'json');
  }

  //xhr (xml http request)
  /*
  possible arguments to be included as properties of the object
  NAME             TYPE      - DESCRIPTION
  "success"        function  - a function to be executed on success
  "failure"        function  - a function to be executed on failure
  "progress"       function  - a function to be executed periodically to report on progress
  "method"         string    - the HTTP request method (GET, POST, HEAD, etc..)
  "url"            string    - the request url
  "data"           *         - data in the form of a string, an object, or a DOM element
  "returnFormat"   string    - the format of the data returned from the request. if left unset, it will be determined by the content type returned from the server
  "sync"           boolean   - performs syncronous request if set to true
  "makeUniqueURL"  boolean   - do not append "?#########" to the url for uniqueness (IE caching issue)
  e.g. xhr('/path/mypage.htm', {"success": functionReference, "data":"x=abc123", "method":"post"});
  */  
  function xhr(strURL, objParameters){
    var objRequest = new httpRequestClass();
    
    if(typeof objParameters != 'object'){
      objRequest.url = strURL;
      objRequest.sync = true;
      return objRequest.execute();
    }
    else{
      for(var key in objParameters){
        if(typeof objRequest[key] == 'undefined')
          throw new Error('ddp.ajax.xhr - Unrecognized parameter name: "' + key + '"');
        else
          objRequest[key] = objParameters[key];
      }
      if(ddp.f.isString(strURL))
        objRequest.url = strURL;
      if(objRequest.sync)
        return objRequest.execute();  //execute the request. return it's result
      else if(objRequest.execute() == true)
        return objRequest; //return the request object;
      else
        return null;
    }
  }
  
  
  /***************************************************************/
  //HTTPRequest
  //performs a get or post http request
  //----arguments----
  //strMethod:        string    -'get' or 'post' or null (defaults to 'get')
  //strURL:           string    -the url (can include name/value arguments. eg. '/path/page.php?name=value&test=1') 
  //strData:          string    -request data in the form of a name/value string ('variableName=variableValue&pizza=yes')
  //                  object    -if you pass a form element in strData, the form will be parsed and stringified automatically!
  //successCallback:  function  -function to be executed when the data is returned.
  //                             data will be returned as the first argument of the function (optional)
  //failureCallback:  function  -function to be executed if the request fails. (optional) 
  //strReturnFormat:  string    -'json' to return a JSON object, 'xml' to return an xmlDocument or
  //                             'text' to return a plain text string (defaults to 'text')
  //progessCallback:  function  -function which is executed periodically during the transfer. (only supported in Mozilla/FF)
  //                             recieves three arguments (percentageComplete, bytesSoFar, bytesTotal)
  //blnSync:          boolean   -when set to true (defaults to false), the request is syncronous and the data is returned from
  //                             the actual function (false is returned on error)
  function HTTPRequest(strMethod, strURL, strData, successCallback, failureCallback, strReturnFormat, progressCallback, blnSync, blnMakeUniqueURL){
    //create a new httpRequestObject object
    var newRequest = new httpRequestClass();
    
    newRequest.success = (typeof successCallback == 'function') ? successCallback : null; //if a success function was specified, use it
    newRequest.progress = (typeof progressCallback == 'function') ? progressCallback : null; //if a progress function was specified, use it
    //newRequest.fnProgress = function(percentage, bytesSoFar, bytesTotal){ if(console) console.log(percentage + '% complete'); };
    newRequest.failure = (typeof failureCallback == 'function') ? failureCallback : null; //if a failure function was specified, use it
    newRequest.data = strData; //then set the httpRequestClass property
    if(strURL && strURL.length && strURL.length > 0)
      newRequest.url = strURL; //set the url property of this object
      
    if(ddp.f.isString(strMethod) && strMethod.length)
      newRequest.method = strMethod.toUpperCase();
      
    if(ddp.f.isString(strReturnFormat)){ //if a format was specified in the arguments
      strReturnFormat = strReturnFormat.toLowerCase(); //change it to lower case
      if(strReturnFormat == 'text' || strReturnFormat == 'json' || strReturnFormat == 'xml') //if it is either json or xml,
        newRequest.returnFormat = strReturnFormat; //then use it (otherwise it will remain 'text')
    }
    
    if(blnMakeUniqueURL == false)
      newRequest.makeUniqueURL = false;
  
    //set the "sychronous execution" flag in the object accordingly
    newRequest.sync = (blnSync) ? true : false;
    if(blnSync)
      return newRequest.execute();  //execute the request.
    else if(newRequest.execute() == true)
      return newRequest; //return the request object;
    else
      return null;
  }
  
  
  //httpRequestClass
  //the wrapper class used to make a request cross-browser compatible
  //basically, set all the properties you need to and then execute() the request.
  function httpRequestClass(){
    this.success = null;  //by default, don't use a success function
    this.progress = null;  //by default, don't use a progress function
    this.failure = null;  //by default, don't use a failure function
    this.method = 'GET'; //by default, use the 'get' method
    this.url = null;
    this.data = null;
    this.returnFormat = 'default'; //if left as 'default' the return type will try to be determined from the content-type in the response heade
    this.sync = false;
    this.makeUniqueURL = true;
    var objThisRequest = this;  //keep a reference to this object
    objThisRequest.http = null;
    var strErrorURL = ''; //the URL that will be reported on errors
        
    //abort
    //abort the HTTPRequest
    this.abort = function(){
      if(objThisRequest.http){
        try{
          objThisRequest.blnAborting = true;
          objThisRequest.http.abort();
          objThisRequest.blnAborting = false;
          return true;
        }
        catch(e){
          objThisRequest.blnAborting = false;
          return false;
        }
      }
      else
        return false;
    };

    
    //failHandler
    //Fired when there is an error with the request
    //----arguments----
    //intNumber:      integer -the error number
    //strDescription: string  -the error description
    this.failHandler = function(intNumber, strDescription){
      if(objThisRequest.progressInterval){
        window.clearInterval(objThisRequest.progressInterval); //clear it
        objThisRequest.progressInterval = null; //and set the reference to it to null
      }
      if(objThisRequest.failure) //if there is a failure specified,
        return objThisRequest.failure(intNumber, strDescription, strErrorURL);  //use it
      else if(!objThisRequest.sync) //if there is no handler specified then just throw the error
        throw new Error('ddp.a.HTTPRequestClass: ' + strDescription + ' (' + intNumber + ') "' + strErrorURL + '"');
      return false;//return false to a syncronous request to indicate that there was a problem
    }
    
    
    //execute
    //takes all the properties that have been setup and performs the request
  	this.execute = function(){
      var http = null;
      
      //create the request in (Firefox/Mozilla/Opera)
      if(typeof XMLHttpRequest == 'function'){
        http = new XMLHttpRequest();
        objThisRequest.objectVersion = 'XMLHttpRequest'; //save the object version
      }
      //create the request (IE)
    	else if(typeof ActiveXObject != 'undefined'){
        var XMLHTTP_IDS = [
          'Msxml2.XMLHTTP.6.0', //installed with IE7. ships with vista out-of-the-box.
          'MSXML2.XMLHTTP.4.0', //designed to support legacy applications.
          'MSXML2.XMLHTTP.3.0', //installed on all Win2k (sp4) and up Microsoft OSs. Does not support "Xml Schema" (XSD 1.0)
          'MSXML2.XMLHTTP.5.0'  //installed with Office 2003 but is off by default in IE7 and causes a "gold bar" to pop up when instanciated in IE7. better than nothing.
        ];
        //'MSXML2.XMLHTTP' //too old to be usable (no support for abort() method)
        //'Microsoft.XMLHTTP'`//too old to be usable (no support for abort(), among other things)
        
        for(var i=0; i<XMLHTTP_IDS.length && !http; i++){
           try{
             http = new ActiveXObject(XMLHTTP_IDS[i]);
             objThisRequest.objectVersion = XMLHTTP_IDS[i]; //save the object version so we can ask about it later
           }
           catch(e){}
        }
    	}
      
      objThisRequest.http = http;
      
      if(!http) //if the object couldn't be created
        return objThisRequest.failHandler(1, 'XMLHTTPRequest object could not be created.');  //fire the failure handler and quit
      
      //stateChangeHandler
      //hook the onreadystatechange event of the request object with our own function (stateChangeHandler)
      //wait for the readyState to change to 4 ("loaded") and make sure the http status is 200 ("OK")
  	  var stateChangeHandler = function(){
        if(http.readyState == 4){  //readyState will be 4 when the document is loaded.
          //if there is a progress interval set,
          if(objThisRequest.progressInterval){
            window.clearInterval(objThisRequest.progressInterval); //clear it
            objThisRequest.progressInterval = null; //and set the reference to it to null
          }
          if(objThisRequest.blnAborting)
            return false;
      		else if(http.status == 200){
            progressHandler(http); //fire the progress handler to make sure we show a progress of 100%
            //if the return type was left as 'default', try to determine the proper return type from the response 'content-type' header
            if(objThisRequest.returnFormat=='default'){
              var strResponseType = http.getResponseHeader('Content-Type'); //get the content-type string from the header
              strResponseType = strResponseType.toLowerCase();
              //if it's a json/javascript content type,
              if(strResponseType.indexOf('application/json') == 0 || strResponseType.indexOf('application/javascript') == 0 || strResponseType.indexOf('text/json') == 0 || strResponseType.indexOf('text/javascript') == 0)
                objThisRequest.returnFormat = 'json'; //set the return type to json
              //if it's an xml content type
              else if(strResponseType.indexOf('application/xml') == 0 || strResponseType.indexOf('text/xml') == 0 || strResponseType.indexOf('application/xhtml+xml') == 0)
                objThisRequest.returnFormat = 'xml'; //set the return type as xml
              else
                objThisRequest.returnFormat = 'text'; //otherwise return plain text
            }
            
      			var result = null; //return null if something goes wrong
            if(objThisRequest.method=='HEAD'){ //if it's a head request,
              if(http.getAllResponseHeaders){ //make sute the requst object supports getting the whole header 
                strTmp = ddp.f.trimWhitespace(http.getAllResponseHeaders()); //get the whole header and remove extra line feeds or spaces on either end
                if(strTmp && strTmp.length){  //if we got a proper string and the string has a length and the length is more than 0
                  var arLines = strTmp.split('\n'); //split the string into an array of lines 
                  result = {}; //at this point we can at least return an empty object
                  for(var i=0; i<arLines.length; i++){  //go through the lines of the header
                    var intPosition = arLines[i].indexOf(':'); //find the first colon
                    //now take the first part(being the item name) and set a property with the same name to the second part (the item value)
                    result[arLines[i].substring(0,intPosition).toLowerCase()] = ddp.f.trimWhitespace(arLines[i].substring(intPosition+1));
                  }
                }
              }
            }
      			else if(objThisRequest.returnFormat == 'json' && http.responseText) //If the return is in JSON format, eval the result before returning it.
     					result = parseJSON(http.responseText);  //parse the string into a json object
      			else if(objThisRequest.returnFormat == 'xml') //If the return is in XML format,
     					result = (http.responseXML.documentElement) ? http.responseXML.documentElement : http.responseXML; //return the responseXML object.
            else if(objThisRequest.returnFormat == 'text' && http.responseText) //otherwise
     					result = http.responseText; //return the plain text string
      			
      			if(objThisRequest.success)  //if a success function was specified
              objThisRequest.success(result);//execute it, passing the data to it.
            objThisRequest.http = null;
            //http = null;
            return result;
      		}
      		else //if the http status wasn't 200, then there was a problem 
      			return objThisRequest.failHandler(http.status, 'HTTP Error'); //fire the failure handler 
      	}
    	};
      
      //progressHandler
      //this is our progress handler, which will be fired periodicaly by the XmlHttpRequest object.
      //we, in turn, will fire the user-defined progress handler and pass it three args: percent complete, bytes recieved and total bytes.
      //----arguments----
      //obj:  object  -an object that is passed from the XmlHttpRequest()
      var progressHandler = function(obj){
        var percentComplete = 0;
        var bytesTotal = 0;
        var bytesSoFar = 0;
        
        if(obj){
          if(typeof obj.totalSize != 'undefined'){ //older style object/properties (pre ff3)
            bytesTotal = obj.totalSize;
            bytesSoFar = obj.position;
          }
          else if(typeof obj.total != 'undefined'){ //using NN based browsers 
            bytesTotal = obj.total;
            bytesSoFar = obj.loaded;
          }
          else if(obj==http){
            try{
              bytesTotal = obj.getResponseHeader('Content-Length');
              //bytesSoFar = http.responseBody.length;
              bytesSoFar = obj.responseText.length;
            }
            catch(e){}
          }
        }
        
        //if we aren't going to end up dividing by zero...
        if(bytesTotal > 0)
          //round the percentage to two decimal places (eg. 25.66)
          percentComplete = roundToDecimalPlace(bytesSoFar / bytesTotal * 100, 2);
        
        if(typeof objThisRequest.progress == 'function') //if the progress function has been defined
          objThisRequest.progress(percentComplete, bytesSoFar, bytesTotal); //execute it with our progress info
      };
      
      function roundToDecimalPlace(intNumber, numberOfPlaces){
        return Math.round(intNumber * Math.pow(10,numberOfPlaces)) / Math.pow(10,numberOfPlaces);
      }

      //if an object is passed
      if(ddp.f.isObject(objThisRequest.data)){
        var objObject = objThisRequest.data;
        //if the object is a DOM element(probably a <form>)
        if(objObject.nodeType && objObject.nodeType==1){
          if(!ddp.forms)//throw an error if the forms module isn't included
            throw new Error('ddp.a.httpRequestClass: The ddp.forms module is required to parse a DOM element');
          //go through the element's children and parse all the name/value pairs from the inputs into a string (using encodeURIComponent())
          objThisRequest.data = ddp.forms.parseForm(objObject);
        }
        else
          objThisRequest.data = serializeObject(objObject); //turn the object into a string of URI encoded name/value pairs
      }
      
      
      //validate the request type
      objThisRequest.method = objThisRequest.method.toUpperCase();
      var arRequestTypes = ['GET','POST','HEAD','OPTIONS','PUT','DELETE','TRACE','CONNECT'];
      for(var i=0, l=arRequestTypes.length; i<=l && objThisRequest.method != arRequestTypes[i]; i++)
        if(i==l)
          throw new Error('ddp.ajax.httpRequestClass - Invalid request type: "' + objThisRequest.method + '"');
          
      //make sure a url was supplied 
  		if(!objThisRequest.url) return objThisRequest.failHandler(2, 'URL argument not supplied');
  		
      //avoid the cache problem in IE by creating a different URL each time
      var strUniqueId = new Date().getTime() + String(Math.random()).replace('.','');
 
      try{
        if(typeof http.onprogress != 'undefined')
          http.onprogress = progressHandler;
        else
          objThisRequest.progressInterval = window.setInterval(function(){progressHandler(http);}, 250);
        if(objThisRequest.method=='POST'){
          var strCompiledURL = objThisRequest.url;
          strErrorURL = strCompiledURL;
          if(objThisRequest.makeUniqueURL){
            strCompiledURL += (strCompiledURL.indexOf('?')+1) ? '&' : '?';
            strCompiledURL += strUniqueId;
          }
          http.open('POST', strCompiledURL, !objThisRequest.sync);
          http.onreadystatechange = stateChangeHandler;
    			http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;'); //Send the proper header information along with the request
    			http.setRequestHeader('Content-length', objThisRequest.data.length);
    			//http.setRequestHeader('Connection', 'close'); //jim says conflicts with IE6 POST??
          http.send(objThisRequest.data);  //send the post request
        }
        else{
          var strCompiledURL = objThisRequest.url;
          if(objThisRequest.data){    //if there's anything in data,
            strCompiledURL += (strCompiledURL.indexOf('?')+1) ? '&' : '?'; //add a "?" if there isn't one, otherwise add a "&"
            strCompiledURL += objThisRequest.data;  //add it to the url
          }
          strErrorURL = strCompiledURL;
          if(objThisRequest.makeUniqueURL){
            strCompiledURL += (strCompiledURL.indexOf('?')+1) ? '&' : '?';
            strCompiledURL += strUniqueId;
          }
          //2083 characters max length of GET request url in IE
          //if(objThisRequest.method == 'GET' && strCompiledURL.length > 2083)
          http.open(objThisRequest.method, strCompiledURL, !objThisRequest.sync); //open the request
          http.onreadystatechange = stateChangeHandler;
          http.send(null);  //and send it
        }
        return (objThisRequest.sync) ? stateChangeHandler() : true;  //return true to indicate that the request was sent
      }
  		catch(e){ //if something goes wrong
  			return objThisRequest.failHandler(-1, e.fileName + ', line ' + e.lineNumber + ', ' + e.name + ': ' + e.message);//fire the failHandler
  		}
  	};
  }
  

  
  /***************************************************************/
  // The parseJSON method takes a string and returns
  // a JavaScript value if the string is a valid JSON text.
  function parseJSON(text){
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;
  
    cx.lastIndex = 0;
  	
    //convert special characters to unicode escaped equivalent
    if(cx.test(text))
    	text = text.replace(cx, function(a){ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); });
  
  	if(/^[\],:{}\s]*$/.
  		test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
  		replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
  		replace(/(?:^|:|,)(?:\s*\[)+/g, ''))){
      
      try{
        //eval the string and return the results
        var objData = eval('(' + text + ')');
        
        //if the result is an object and it contains a property named "ddpSchema", then recursively
        //convert the data to date objects, decoded strings, boolean values etc.. following the schema.  
        return (objData && objData.ddpSchema) ? _convertData(objData, objData.ddpSchema) : objData;  
      }
      catch(objEvalError){
        var strErr = 'Error: ddp.a.parseJSON: Error evaling JSON data';
        try{ console.log(strErr); }
        catch(e){ alert(strErr); }
        throw(objEvalError);
      }
    }
  	
  	return false;
  };
  
// Return a boolean value telling whether // the first argument is a string. 

  function _convertData(objData, objDataTypes){
    //if the object passed is an array
    //if(typeof objData == 'object' && typeof objData.constructor == 'object' && objData.constructor == Array){
    if(ddp.f.isArray(objData)){
      //iterate through it 
      for(var i=0; i<objData.length; i++)
        //and convert each index (maintaining the same level of depth in objDataTypes
        objData[i] = _convertData(objData[i], objDataTypes)
      return objData;
    }
    //if the object passed is an object but not an array
    //else if(typeof objData == 'object'){
    else if(objData && typeof objData == 'object' && !ddp.f.isString(objData)){
      //go through the properties
      for(property in objData){
        //and if the property has a corresponding property in the ddp schema
        if(objDataTypes[property])
          //then convert the property
          objData[property] = _convertData(objData[property], objDataTypes[property]);
      }
      return objData;
    }
    //if the object passed is not an object, just a primitive data type
    else{
      switch(objDataTypes){
        case 'date': //for 'date' types
          if(ddp.f.isString(objData) && objData.indexOf('ddpDate') == 0){
            var arDateParts = objData.split(' ');
            arDateParts.splice(0, 1); //splice out the ddpDate marker
            for(var i=arDateParts.length; i<7; i++)
              arDateParts[i] = 0;
            return new Date(arDateParts[0], arDateParts[1], arDateParts[2], arDateParts[3], arDateParts[4], arDateParts[5], arDateParts[6])
          }
          else if(isFinite(objData)){  //if it's just a number
            var returnValue = new Date();//create a new date object
            //assume we were passed the number of milliseconds since
            //midnight january 1st 1970 and set the date using "setTime"
            returnValue.setTime(objData);
            return returnValue;
          }
          else{
            //try and return the value from the DDP date parsing method
            var d = ddp.f.parseDateString(objData);
            //return either the successfully parsed date or the string itself
            return d ? d : objData;
          } 
        case 'boolean':
          return (objData || (objData.toLowerCase && objData.toLowerCase() == 'true') ) ? true : false;
        case 'number':
          return (ddp.f.isString(objData)) ? Number(objData) : objData;
        case 'string':
          return (objData==null) ? '' : objData;
        default:
          return objData;
      }
    }
  }
  
  
  
  /**************************************************/
  //loadXmlDocument
  function loadXmlDocument(strURL, fnSuccess){
    var docXML = null;
    if(document.implementation && document.implementation.createDocument){
      try{
        docXML = document.implementation.createDocument('', '', null);
        ddp.f.addEvent(docXML, 'load', function(){ fnSuccess(docXML); });
        docXML.load(strURL);
        return true;
      }
      catch(e){}
    }
    else if(window.ActiveXObject){
      try{
        docXML = new ActiveXObject("Microsoft.XMLDOM");
        docXML.async = true;
    	  docXML.onreadystatechange = function(){ if(docXML.readyState == 4) fnSuccess(docXML);	};
        docXML.load(strURL);
        return true;
      }
      catch(e){}
    }
    return false;
  }
  
  
  /**************************************************/
  //submitToIframe
  //
  //
  function submitToIframe(elForm, fnResponse, strReturnType){
    var strUniqueId = 'ddpSubmitToIframe' + String(Math.random()).replace('.','');
    //var strIframeSrc = 'about:blank'; //gets reported in IE6 as an unencrypted item under https protocol
    var strIframeSrc = 'javascript: false;';
    var elIFrame = document.createElement('iframe');
    
    strReturnType = (typeof strReturnType == 'string') ? strReturnType.toLowerCase() : 'text';
    
    elIFrame.setAttribute('src', strIframeSrc);
    elIFrame.setAttribute('id', strUniqueId);
    elIFrame.setAttribute('NAME', strUniqueId);
    elIFrame.style.display = 'none';
    document.getElementsByTagName('body')[0].appendChild(elIFrame);
    //bug fix for IE (if left out IE opens a new window instead of using the new iframe)
    try{ window.frames[strUniqueId].name = strUniqueId; }catch(e){ }
    
    //add a handler to the iframe's load event
    ddp.f.addEvent(elIFrame, 'load', function(){
      //get the iframe's document (cross-browser wise)
      var elDocument = (elIFrame.contentDocument)?(elIFrame.contentDocument):((elIFrame.contentWindow)?(elIFrame.contentWindow.document):(self.frames[strUniqueId].document));
      
      if(elDocument.location.href != strIframeSrc){ //if the iframe's url is not the one we just gave it
        if(typeof fnResponse == 'function'){
          var returnValue;
          if(strReturnType == 'json')
            returnValue = parseJSON(elDocument.body.innerHTML);
          else if(strReturnType == 'xml')
            returnValue = elDocument;
          else
            returnValue = elDocument.body.innerHTML;
          fnResponse(returnValue); //fire the response handler
        }
        ddp.f.removeEvent(elIFrame, 'load', arguments.callee); //remove this handler
        //remove the iframe since we don't need it anymore
        //but wait 1 second so firefox will stop showing activity
        setTimeout(function(){ elIFrame.parentNode.removeChild(elIFrame); }, 1000); 
      }
    });
    
    elForm.setAttribute('target', strUniqueId);
    elForm.submit();
  }
  
  
  
	
  /**************************************************/
  //createAjaxIframe
  //Creates an IFRAME element for transfering data to the server and 
  //sets a timeout to remove it a specified number of seconds after
  //it is created.
  function createAjaxIframe(secondsBeforeRemoval, url){
  	var body = document.getElementsByTagName('BODY')[0];
  	var f = document.createElement('IFRAME');
  	f.src = url;
  	f.style.display='none';
  	var timeNow = new Date().getTime();
  	f.id = 'frame' + timeNow;
  	var x = setTimeout('document.getElementById(\'' + f.id + '\').parentNode.removeChild(document.getElementById(\'' + f.id + '\'));', secondsBeforeRemoval * 1000);
  	body.appendChild(f);
  }
  
  
  /**************************************************/
  //serializeObject
  //converts an object with properties to an encodeURIComponent'd name/value string
  //onlyOwnProperties is optional. if set to true, it stops serializeObject from outputing inherited properties
  function serializeObject(objObject, onlyOwnProperties){
    //array to hold the name/value pair strings
    var arNameValuePairs = [];
    //if the value was passed in as "true" then set it true, otherwise false.
    onlyOwnProperties = (onlyOwnProperties==true) ? true : false;
    
    //go through the object's properties, one by one
    for(propertyName in objObject){
      //try{  console.log('name:' + propertyName + ' hop:' + objObject.hasOwnProperty(propertyName)); } catch(e){}
      //if the "onlyOwnProperties" flag is set to true, don't include inherited properties in the return string 
      //and if the browser doesn't support the "hasOwnProperty" method, just do it anyway 'cause there's no way to tell
      //if(Object.hasOwnProperty.call(value, k)) //from Jim's implementation
      if(!onlyOwnProperties || !objObject.hasOwnProperty || objObject.hasOwnProperty(propertyName)){
        //if the value is null
        if(objObject[propertyName] === null)
          //output a string with 'null' in it
          arNameValuePairs.push(encodeURIComponent(propertyName) + '=' + encodeURIComponent('null'));
        //if it's an array,
        else if(ddp.f.isArray(objObject[propertyName])){
          //go through the array elements
          for(var i=0, l=objObject[propertyName].length; i<l; i++)
            //and format the string properly by repeating the name with each value
            arNameValuePairs.push(encodeURIComponent(propertyName) + '=' + encodeURIComponent(objObject[propertyName][i]));
        }
        //if it's a regular object (and not a string)
        else if(!ddp.f.isString(objObject[propertyName]) && typeof objObject[propertyName] == 'object')
          //substitute a string containing '[Object]'
          arNameValuePairs.push(encodeURIComponent(propertyName) + '=' + encodeURIComponent('[Object]'));
        //if it's a function
        else if(typeof objObject[propertyName] == 'function')
          //output the return value of it's toString() function or maybe just '[Function]' but whatever
          arNameValuePairs.push(encodeURIComponent(propertyName) + '=' + encodeURIComponent(objObject[propertyName].toString()));
        //otherwise
        else
          //just use it's plain ol' value
          arNameValuePairs.push(encodeURIComponent(propertyName) + '=' + encodeURIComponent(objObject[propertyName]));
      }
    }
    //put the pairs together, seperated by an ampersand
    return arNameValuePairs.join('&');
  }
  

/**************************************************/
//Export the public functions to a public namespace
/**************************************************/

//Exports go here
var ddpns = ddp.a;

//remove when we have found them all
//
ddpns.parseForm = function(objForm){ try{ console.log('old reference to ddp.a.parseForm'); } catch(e){ alert('old reference to ddp.AJAX.parseForm'); } return ddp.forms.parseForm(objForm); };

ddpns.loadJSON = addHeaderScript;
ddpns.addHeaderScript = addHeaderScript;
ddpns.request = request;
ddpns.requestPost = requestPost;
ddpns.HTTPRequest = HTTPRequest;
ddpns.xhr=xhr;
ddpns.httpRequestClass = httpRequestClass;
//ddpns.httpRequest = HTTPRequest; //just an alias. try removing it and see if causes problems
ddpns.parseJSON = parseJSON;
ddpns.loadXmlDocument = loadXmlDocument;
ddpns.submitToIframe = submitToIframe;
ddpns.createAjaxIframe = createAjaxIframe;
ddpns.serializeObject = serializeObject;
})();
