/**
 * the postman who handles all the datatraffic to and from the server
 */
var post = new Object();
post.METHOD = 'POST';
//post.CONTENT_TYPE = '';
post.Postman = function() {
 this.url = marnixkerk.URL + "/ServerSideScripts/postoffice.php";
 this.requestQue = [];
};
post.Postman.prototype = {
 postData : function(request) {
 
  // add the sessionid to all packages if available
  if (marnixkerk.sessionID) {
   request.addParam("sessionID",marnixkerk.sessionID);
  }
 
  // set id to the request
  request.setID(new Date().getTime());
  
  // make sure the uniquity of the id
  while (this.requestQue[request.getID()] instanceof Object) {
   request.setID(new Date().getTime());
  }
  
  // set the params
  var paramStr = "type=" + request.getType();
  var params = request.getParams();
  paramStr += "&id=" + request.getID();
  if (request.getObjRef()) {
   paramStr += "&obj_ref=" + request.getObjRef();
  }
  for (var i=0;i<params.length;i++) {
   paramStr += "&" + params[i]['name'] + "=" + this.URLencode(params[i]['value']);
  }

  // fire request
  this.requestQue[request.getID()] = new net.ContentLoader(this.url,this.submitHandledRequest,request.getCallBack(),false,post.METHOD,paramStr);

  // give feedback to user
  this.setLoading(true);
 },
 setLoading : function(bool) {
  if (bool) {
  
   // set loading-image active
   setLoadingImageOnload(true);
  } else {
  
   // set loading-image idle
   setLoadingImageOnload(false);
  }
 },
 /**
  * Submit when an request is handled
  */
 submitHandledRequest: function() {
 
  // remove request from que
  var postman = marnixkerk.POSTMAN;
  postman.deleteRequest(this.response.getID());

  // set image idle (if no more requests are processed)
  postman.reCheckPendingRequests();
 },
 /**
  * Stop the loadingimage if there are no more pending requests
  */
 reCheckPendingRequests : function() {
  if (this.requestQue.length < 1) {
   this.setLoading(false);
  }
 },
 /**
  * delete an request
  */
 deleteRequest : function(id) {
  delete this.requestQue[id];
 },
 /**
  * encode URL
  * @param str string to be escaped
  * @return urlencoded string
  */
 URLencode : function(str) {
  return escape(str).replace(/\+/g,'%2B').replace(/\"/g,'%22').replace(/\'/g,'%27');
 }
}

/**
 * The contentloader
 */
var net = new Object();
net.READY_STATE_UNITIALIZED = 0;
net.READY_STATE_LOADING = 1;
net.READY_STATE_LOADED = 2;
net.READY_STATE_INTERACTIVE = 3;
net.READY_STATE_COMPLETE = 4;
/**
 * @param controller The controller of the webpage
 * @param url The url of the target file (at the server)
 * @param onload this function is called first after recieving data
 * @param onerror this function is called when something went wrong
 * @param method specify method for datatransfer: 'GET' by default
 * @param add params who will be sended to the target file as variables
 * @param contentType specify the content type.
 */
net.ContentLoader = function(url,handleRequest,onload,onerror,method,params,contentType) {
 this.url = url;
 this.error = false;
 this.sessionError = false;
 this.req = null;
 this.handleRequest = handleRequest;
 this.onload = (onload) ? onload : this.dummy;
 this.onerror = (onerror) ? onerror : this.defaultError;
 this.loadXMLDoc(url,method,params,contentType);
 this.response = false;
};
net.ContentLoader.prototype = {
 loadXMLDoc : function(url,method,params,contentType) {
  if (! method) {
   method = 'GET';
  }
  if (! contentType && method == "POST") {
   contentType = 'application/x-www-form-urlencoded';
  }
  if (window.XMLHttpRequest) {
   this.req = new XMLHttpRequest();
  } else if (window.ActiveXObject) {
   this.req = new ActiveXObject("Microsoft.XMLHTTP");
  }
  if (this.req) {
   try {
    var loader = this;
    this.req.onreadystatechange = function(){
     loader.onReadyState.call(loader);
    }
    this.req.open(method,url,true);
    if (contentType){
     this.req.setRequestHeader("Content-Type",contentType);
    }
    this.req.send(params);
   } catch (err) {
    this.onerror.call(this);
   }
  }
 },
 onReadyState : function() {
  var req = this.req;
  var ready = req.readyState;
  if (ready == net.READY_STATE_COMPLETE) {
   var httpStatus = req.status;
   if (httpStatus == 200 || httpStatus == 0) {

    // parse response xml
    this.parseXML.call(this);
    
    // handle request, delete request from que etc..
    this.handleRequest.call(this);

    // call callbackfunction if no error occurred
    if (this.error) {
    
     //TODO userfrendly errorhandling
     showError("Helaas, de volgende fout is opgetreden: " + this.error);
    } else if (this.sessionError) {
     handleSessionError(this.sessionError);
    } else {
     this.onload(this.response);
    }
   } else {
    this.onerror.call(this);
   }
  }
 },
 /**
  * Default error function
  */
 defaultError : function() {
  alert("error fetching data!"
   + "\n\nreadyState: " + this.req.readyState
   + "\nstatus: " + this.req.status
   + "\nheaders: " + this.req.getAllResponseHeaders());
 },
 /**
  * Dumy function
  */
 dummy : function() {
  // noop
 },
 /**
  * Parse response xml
  */
 parseXML : function(contentLoader) {
  var xmlDoc = this.req.responseXML;
  var elDocRoot = xmlDoc.getElementsByTagName("response")[0];
  if (elDocRoot) {
   this.response = new Response();

   // parse header
   var elHeader = xmlDoc.getElementsByTagName("header")[0];
   for (var i=0; i<elHeader.childNodes.length; i++) {
    elChild = elHeader.childNodes[i];
    this.response.addHeaderItem(elChild.nodeName,an_nodeValue(elChild));
    
    // handle errors
    if (elChild.nodeName == 'error') {
     this.error = an_nodeValue(elChild);
    } else if (elChild.nodeName == 'session_error') {
     this.sessionError = an_nodeValue(elChild);
    }
   }
   
   // parse body
   var elBody = xmlDoc.getElementsByTagName("body")[0];

   // interate through level one tags
   for (var i=0; i<elBody.childNodes.length; i++) {
    var levelOneChild = elBody.childNodes[i];
    
    // a node is or a branch or a leave, so check (for) the first element; index = 0
    if (levelOneChild.childNodes[0].hasChildNodes()) {
     var levelOneParent = [];
     var levelOneParentName = levelOneChild.nodeName;
     
     // interate through level two tags
     for (var ii=0; ii<levelOneChild.childNodes.length; ii++) {
      var levelTwoChild = levelOneChild.childNodes[ii];
      
      if (levelTwoChild.childNodes[0].hasChildNodes()) {
       var levelTwoParent = [];
       var levelTwoParentName = levelTwoChild.nodeName;
       
       // interate through level three tags
       for (var iii=0; iii<levelTwoChild.childNodes.length; iii++) {
        var levelThreeChild = levelTwoChild.childNodes[iii];
        levelTwoParent[levelThreeChild.nodeName] = this.toHTMLChars(an_nodeValue(levelThreeChild));
       }
       levelOneParent[levelTwoChild.nodeName] = levelTwoParent;
      } else {
       levelOneParent[levelTwoChild.nodeName] = this.toHTMLChars(an_nodeValue(levelTwoChild));
      }
     }
     this.response.addBodyItem(levelOneParentName,levelOneParent);
    } else {
     this.response.addBodyItem(levelOneChild.nodeName,this.toHTMLChars(an_nodeValue(levelOneChild)));
    }
   }
  }
 },
 /**
  * Convert string to HTML parsable chars
  * @param str to be converted
  * @return converted string
  */
 toHTMLChars : function(str) {
  
  // its important to start with this: '&' character because it is used as a first occurence by all other entities!!
  var entities = ['&amp;','&lt;','&gt;','&#039;','&quot;','&uuml;','&euml;'];
  var chars = 	 ['&'    ,'<'   ,'>'   ,"'"    ,'"'      , 'ü'    ,'ë'     ];
  str = this.replaceEntity(str,entities,chars);
  
  // parse unicode entities
  entities = 	['%u201C','%u201D','%u2013','%u2018','%u2019','%u20AC','%u0451', '%u2026']; 
  chars = 	['“'     ,'”'     ,'–'     ,'‘'     ,'’'     ,'€'     ,'ë'     ,   '...' ];
  str = this.replaceEntity(str,entities,chars);
  
  // finaly convert html special characters like ë,é,etc.
  /*
  function disabled doesn't work out in IE7 
  var div = document.createElement('div');
  div.innerHTML = str;
  str = div.innerHTML;
  */
  return str;
 },
 /**
  * Replace entity
  * @param str to be converted
  * @param entities to be replaced
  * @param chars the replacement values
  * @return converted string
  */
 replaceEntity : function(str,entities,chars) {
  for (var i=0; i<entities.length; i++) {
   while (str.indexOf(entities[i]) > -1) {
    var tmp=str.replace(entities[i],chars[i]);
    str=tmp;
   }
  }
  return str;
 },
 /**
  * Get response
  */
 getResponse : function() {
  return this.response;
 }
}





/**
 * The request-object
 */
var Request = function(type,obj_ref) {
 this.id = false;
 this.obj_ref = (obj_ref) ? obj_ref : false;
 this.type = type;
 this.params = [];
 //this.callBack;
};
Request.prototype = {
 /**
  * Add an parameter to the request
  */
 addParam : function(pName,pValue) {
  var request = {name : pName,value : pValue};
  an_append(request,this.params);
 },
 /**
  * Set the function that must be called after completion
  */
 setCallBack : function(callBack) {
  this.callBack = callBack;
 },
 /**
  * Set the function that must be called after completion
  */
 getCallBack : function(callBack) {
  return this.callBack;
 },
 /**
  * set ID
  */
 setID : function(id) {
  this.id = id;
 },
 /**
  * get ID
  */
 getID : function() {
  return this.id;
 },
 /**
  * get Object reference
  */
 getObjRef : function() {
  return this.obj_ref;
 },
 /**
  * get type
  */
 getType : function() {
  return this.type;
 },
 /**
  * get params
  */
 getParams : function() {
  return this.params;
 }
}

/**
 * parse xml-body
 * @param xml-body node
 * @return object - array
 */
var parseXML = function(xmlBody) {

 /* BNF
  <xmldoc. ::= <root>
  <root>   ::= <leave> | <branch>
  <leave>  ::= 
 */
 
 return ['empty'];
}



/**
 * The response-object
 */
var Response = function() {
 this.headerContent = [];
 this.bodyContent = [];
 this.bodyContentNum = [];
};
Response.prototype = {
 /**
  * Add an header-parameter to the response
  */
 addHeaderItem : function(name,value) {
  this.headerContent[name] = value;
 },
  /**
  * Add an body-parameter to the response
  */
 addBodyItem : function(name,value) {
  this.bodyContent[name] = value;
  an_append(value,this.bodyContentNum);
 },
  /**
  * get ID
  */
 getID : function() {
  if (! this.headerContent.error) {
   return this.headerContent['id'];
  } else {
   return false;
  }
 },
 /**
  * Return the headerItems
  * @return an array with the header items
  */
 getHeaderItems : function() {
  return this.headerContent;
 },
 /**
  * Return the bodyItems
  * @return an associative array with the body items
  */
 getBodyItems : function() {
  return this.bodyContent;
 },
 /**
  * Return the bodyItems
  * @return an numeric array with the body items
  */
 getBodyItemsNum : function() {
  return this.bodyContentNum;
 }
}
