//main ajax handling
function XDocAjaxHandler(n){
    //timer for call later calls
    var nloads = 0;
    var loaderImgElement = null;
    var xdoc_skin = "default";
    var debug = false;
    var servicesUrl = "";
    var serviceExtension = "";
    var workSequential = false;
    var isWorking = false;
    var jobs = [];
    var oTimer = null;
    var Name = n ? n : "xdoc_ajax";
    
    
    this.setWorkSequential = function(bVal){
        workSequential = bVal;
    }

    this.setSkin = function(skin){
        xdoc_skin = skin;
    }

    this.setDebug = function(bVal){
        debug = bVal;
    }

    this.setServicesUrl = function(sVal){
        servicesUrl = sVal;
    }

    this.setServiceExtension = function(ext){
        serviceExtension = "." + ext;
    }

    this.doStart = function(ajaxRequest) {
	    loaderImgElement = loaderImgElement ? loaderImgElement : document.getElementById("xdoc_loadingImg");
	    if(nloads == 0){
    	    if(loaderImgElement) loaderImgElement.src = xdoc_basepath + "/xdoc/out/"+xdoc_skin+"/img/loaderOn.gif";
        }
        ++nloads;
    }

    this.doEnd = function(ajaxRequest) {
	    loaderImgElement = loaderImgElement ? loaderImgElement : document.getElementById("xdoc_loadingImg");
	    --nloads;
	    if(nloads <= 0){
    	    if(loaderImgElement) loaderImgElement.src = xdoc_basepath + "/xdoc/out/"+xdoc_skin+"/img/loaderOff.png";
    	    nloads = 0;
        }
        if(ajaxRequest) ajaxRequest.backRef.handleJobs();
    }

    this.basicErrorHandler = function(ajaxRequest, exception) {
	    loaderImgElement = loaderImgElement ? loaderImgElement : document.getElementById("xdoc_loadingImg");
        alert("An exception has occurred:" + exception);
        --nloads;
	    if(nloads <= 0){
    	    if(loaderImgElement) loaderImgElement.src = xdoc_basepath + "/xdoc/out/"+xdoc_skin+"/img/loaderOff.png";
    	    nloads = 0;
        }
        if(ajaxRequest) ajaxRequest.backRef.handleJobs();
    }

    this.addjustUrl = function(url, holder, handler, params){
    	var purl = "";
    	if(params){
    		for(var k in params){
    			purl += "&" + k + "=" + params[k];
    		}
    	}
    	if(holder == null){
    		//service call with no UI
    		var v = url.split("?");
    		if(handler != null && typeof(window[handler]) == "function"){
                return servicesUrl + "/" + v[0] + serviceExtension + "?handler=" + handler + (v.length == 2 ? "&" + v[1] : "") + purl;
            }
    	}else if(document.getElementById(holder)){
    		//alert(url + "---" + handler + "--" + typeof(window[handler]));
        	var v = url.split("?");
            if(handler != null && typeof(window[handler]) == "function"){
                return servicesUrl + "/" + v[0] + serviceExtension + "?target=" + holder + "&handler=" + handler + (v.length == 2 ? "&" + v[1] : "") + purl;
            }else{
                return servicesUrl + "/" + v[0] + serviceExtension + "?target=" + holder + (v.length == 2 ? "&" + v[1] : "") + purl;
            }
        }else{
            //alert("Missing destination element:["+holder+"] for ajax call!");
            return "";
        }
    }

    this.addjustFormUrl = function(url){
    	var v = url.split("?");
        return servicesUrl + "/" + v[0] + serviceExtension + ((v.length == 2) ? "?" + v[1] : "");
    }
    
    
    this.handleJobs = function(){
    	if(this.oTimer) clearTimeout(this.oTimer);
    	if(jobs.length > 0){
    		var j = jobs[0];
    		jobs.splice(0,1);
    		isWorking = false;
    		if(j.t == 0){
    			this.doRequest(j.u, j.h, j.ha, j.p);
    		}else{
    			this.doFormRequest(j.u, j.e);
    		}
    	}else{
    		isWorking = false;
    	}
    }
	
	
    this.doRequest = function(url, holder, handler, params) {
        var nUrl = this.addjustUrl(url, holder, handler, params);        
        if(nUrl == "") return;
        
        if(workSequential){
        	//handle possible cocurency
        	if(isWorking){
        		//save job
        		jobs.push({t:0, u:url, h:holder, ha:handler, p:params});
        		//force 2 seconds jobs check
        		if(oTimer) clearTimeout(oTimer);
				oTimer = setTimeout(Name+".handleJobs()", 2000);
        		//leave
        		return;
        	}else{
        		isWorking = true;
        	}
        }
        var ajaxRequest = new AjaxRequest(nUrl);
        ajaxRequest.setErrorHandler(this.basicErrorHandler);
        ajaxRequest.setPreRequest(this.doStart);
        ajaxRequest.setPostRequest(this.doEnd);
        if(debug) ajaxRequest.setEchoDebugInfo();
        ajaxRequest.backRef = this;
        ajaxRequest.sendRequest();
    }

    this.doFormRequest = function(url, elm) {
    	var nUrl = this.addjustFormUrl(url);
    	 if(nUrl == "") return;
    	
    	if(workSequential){
        	//handle possible cocurency
        	if(isWorking){
        		//save job
        		jobs.push({t:1, u:url, e:elm});
        		//force 2 seconds jobs check
        		if(oTimer) clearTimeout(oTimer);
				oTimer = setTimeout(Name+".handleJobs()", 2000);
        		//leave
        		return;
        	}else{
        		isWorking = true;
        	}
        }
        var ajaxRequest = new AjaxRequest(nUrl);
        ajaxRequest.setErrorHandler(this.basicErrorHandler);
        ajaxRequest.setPreRequest(this.doStart);
        ajaxRequest.setPostRequest(this.doEnd);
        //make form
        if(elm.tagName.toLowerCase() != "form"){
            var frm = document.createElement("form");
            var c = elm.childNodes;
            for(var n = 0; n < c.length; n++){
                frm.appendChild(c[n].cloneNode(true));
            }
        }else{
            frm = elm;
        }
        ajaxRequest.addFormElements(frm);
        if(debug) ajaxRequest.setEchoDebugInfo();
        ajaxRequest.backRef = this;
        ajaxRequest.sendRequest();
    }

    this.getFormRequest = function(frm){
        var ajaxRequest = new AjaxRequest("");
        return ajaxRequest.getFormElements(frm);
    }

    this.callLater = function(what, time){
	    setTimeout(what+'()',time);
    }

    this.callLaterP = function(what, param, time){
	    setTimeout(what+'("'+param+'")',time);
    }
};