function EasyAjax() {

    //settings
    this.timeout=300000;            // request timeout in millisecs
	
	//request container
	this.requests = new Array();    // request container
    this.reqnextid = 0;                  // next request identifier
    this.semafor = true;            // semafor to support parallel requests
	
	// autorefresh container
    this.autorefreshes = new Array();	// autorefresh container
	this.refnextid = 0;					// next autorefresh identifier
	
    // creates request object, performs new request, set autorefresh if needed
    this.request = function(responsefile, result, paramdiv, autorefresh, confirmationtext) {
        this.cleanUpRequests();
        if(confirmationtext == undefined || confirmationtext == null || confirm(confirmationtext)) {
            this.semaforStart();
            var request = new this.EasyAjaxRequest(this.reqnextid, responsefile, result, paramdiv);
            this.requests.push(request);
            ++this.reqnextid;
            this.semaforEnd();
            request.doRequest();
        }
		
		if(autorefresh!=null && autorefresh!=undefined) {
			this.semaforStart();
			var refresh = new this.AutoRefresh(this.refnextid, responsefile, result, paramdiv, autorefresh, confirmationtext);
			this.autorefreshes.push(refresh);
			++this.refnextid;
			this.semaforEnd();
			refresh.beginref(autorefresh);
		}
    }

    // cleans up stuck requests
    this.cleanUpRequests = function() {
        this.semaforStart();
        for(i=0; i<this.requests.length; ++i) {
            current = new Date().getTime();
            if(current-this.requests[i].timestamp>this.timeout)
                this.requests.splice(i, 1);
		}
		this.semaforEnd();
    }
        
    // returns request object with the specified id 
    this.getRequest = function(id) {
        this.semaforStart();
        request = this.requests[this.getPos(id)];
        this.semaforEnd();
        return request;
    }
    
    // deletes request object with the specified id
    this.delRequest = function(id) {
        this.semaforStart();
        this.requests.splice(this.getPos(id), 1);
        this.semaforEnd();
    }
    
    // returns position of the specified request object
    this.getPos = function(id) {
        for(i=0; i<this.requests.length; ++i) 
            if(this.requests[i].id == id)
                return i;
        throw "Request not found";
    }
    
    // semafor handling (supports parallel request processing)
    this.semaforStart = function() {
        while(this.semafor == false)
            this.pause(1);
        this.semafor = false;
     }   
        
    
    this.semaforEnd = function() {
        this.semafor = true;
    }
    
    this.pause = function(milli) {
        var date = new Date();
        do { 
            newdate = new Date();
        }
        while(newdate-date<milli);
    }
	
	
	// Ajax request object definition
	this.EasyAjaxRequest = function(id, responsefile, result, paramdiv) {
	
		
		
        // settings
        this.loadMessage = null; // loading message
		this.boundaryString = 'EasyAjax.Net';
        this.boundary = '--' + this.boundaryString;

        // parameters
        this.id = id;
        this.responsefile = responsefile;
        this.result = result;
        this.paramdiv = paramdiv;
        this.timestamp = new Date().getTime();

        // xmlhttp object
        this.xmlhttp;
	
        // prepare and perform ajax request
        this.doRequest = function() {
            var url = this.getUrl();
            var querystring = this.getQueryString();
            var actionfunction = this.getActionFunction();
            this.xmlhttp = this.getXmlHttp(url, querystring, actionfunction);
            if(this.loadMessage != null && typeof(this.result)!='function')
                document.getElementById(this.result).innerHTML = this.loadMessage;
            this.xmlhttp.send(querystring);
        }
	
        // returns listener function object
        this.getActionFunction = function() {
            var actionfunction;
            if(typeof(this.result)=='string')
                actionfunction = new Function("request = easyajax.getRequest("+this.id+");\nif(request.xmlhttp.readyState == 4 && request.xmlhttp.status == 200)\n{\ndocument.getElementById(\""+this.result+"\").innerHTML = request.xmlhttp.responseText;\n easyajax.delRequest("+this.id+");\n}");
            else if(typeof(this.result) == 'function')
                actionfunction = new Function("request = easyajax.getRequest("+this.id+");\nif(request.xmlhttp.readyState == 4 && request.xmlhttp.status == 200)\n{\nrequest.result(request.xmlhttp.responseText);\n easyajax.delRequest("+this.id+");\n}");
            return actionfunction;
        }
	
        // returns response url
        this.getUrl = function() {
            connectchar = this.responsefile.indexOf('?') != -1 ? '&' : '?';
            var url = this.responsefile + connectchar + "timeStamp=" + this.timestamp;
            return url;
        }
	
        // returns html parameter nodes (textarea, select, input fields)
		this.getFields = function() {
            pdiv = document.getElementById(this.paramdiv);
            var fieldtypes = new Array("input", "textarea", "select");
            fields = new Array();
            for(typeid = 0; typeid<fieldtypes.length; ++typeid) {
                fieldtype = fieldtypes[typeid];
				nodes = pdiv.getElementsByTagName(fieldtype);
				for(nodeid=0; nodeid<nodes.length; ++nodeid) {
					node = nodes[nodeid];
					if(fieldtype != "input" || (fieldtype == "input" && node.type!="button" && node.type!="file" && ((node.type!="checkbox" && node.type!="radio") || (node.checked))))
						fields.push(node);
				}
			}
            return fields;
        }
	
        // returns ajax querystring
        this.getQueryString = function() {
            querystring = '';
            if(this.paramdiv != null && this.paramdiv != undefined) {
                var fields = this.getFields();
                for(i=0; i<fields.length; ++i) {
                    var node = fields[i];
                    if(node.name != "" && node.type != "file") {
                        querystring += this.boundary + '\n';
                        querystring += 'Content-Disposition: form-data; name="' + node.name + '"' + '\n\n';
                        querystring += node.value + '\n';
                        querystring += this.boundary + '\n';
                    }
                }
            }
            return querystring;
        }
	
        // returns prepared XmlHttp or ActiveX object
        this.getXmlHttp = function(url, querystring, actionfunction) {
            var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP.3.0");
            method = (this.paramdiv == null || this.paramdiv == undefined) ? "GET" : "POST";
            xmlhttp.open(method, url, true);
            xmlhttp.onreadystatechange = actionfunction; 
            xmlhttp.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + this.boundaryString + "\"");  
            xmlhttp.setRequestHeader("Connection", "close");
            xmlhttp.setRequestHeader("Content-length", querystring.length);
            return xmlhttp;
        }
    }
	
	// autorefresh object
	this.AutoRefresh = function(id, responsefile, result, paramdiv, autorefresh, confirmationtext) {
	
		this.timer = null;
		
		this.id = id;
		this.responsefile = responsefile;
		this.result = result;
		this.paramdiv = paramdiv;
		this.autorefresh = autorefresh;
		this.confirmationtext = confirmationtext;
		
		this.beginref = function() {
			setInterval("easyajax.request(easyajax.autorefreshes["+this.id+"].responsefile, easyajax.autorefreshes["+this.id+"].result, easyajax.autorefreshes["+this.id+"].paramdiv, null, easyajax.autorefreshes["+this.id+"].confirmationtext);", this.autorefresh);
		}
		
		
	}
}

var easyajax = new EasyAjax();
