function getXMLHTTP() {
    var request = false;
    if (window.XMLHttpRequest) {
        if (typeof XMLHttpRequest != 'undefined')
            try {
                request = new XMLHttpRequest();
            } catch (e) {
                request = false;
            }
    } else if (window.ActiveXObject) {
        try {
            request = new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
            try {
                request = new ActiveXObject('Microsoft.XMLHTTP');
            } catch (e) {
                request = false;
            }
        }
    }
    return request;
}
function Remote(assemblyName,className,methodName,callBackFunction){
	var async=(callBackFunction!=null);
	var http=getXMLHTTP();
	var origArguments;
	if (async){
	    http.onreadystatechange = function () {
	        if (http.readyState == 4) {
	            if (http.status == 200)
	                intermed(http, callBackFunction, origArguments);
	        }
	    };
	}
	this.usePost=true;//otherwise uses HTTP GET
	this.assemblyName=assemblyName;
	this.className = className;
	this.methodName = methodName;
	this.evaluate = function () {
	    origArguments = arguments;
	    var msg = "<msg struct='true'><asm>" + this.assemblyName + "</asm><class>" + this.className + "</class><method>" + this.methodName + "</method>";
	    for (var i = 0; i < arguments.length; i++) {
	        if (arguments[i] == null)
	            msg += "<null/>";
	        else {
	            switch (arguments[i].constructor) {
	                case String:
	                    msg += "<string><![CDATA[" + arguments[i] + "]]></string>";
	                    break;
	                case RefString:
	                    msg += "<stringR><![CDATA[" + arguments[i].value + "]]></stringR>";
	                    break;
	                case Int:
	                    msg += "<int>" + arguments[i].value + "</int>";
	                    break;
	                case RefInt:
	                    msg += "<intR>" + arguments[i].value + "</intR>";
	                    break;
	                case Double:
	                    msg += "<double>" + arguments[i].value + "</double>";
	                    break;
	                case RefDouble:
	                    msg += "<doubleR>" + arguments[i].value + "</doubleR>";
	                    break;
	                case Bool:
	                    msg += "<bool>" + arguments[i].value + "</bool>";
	                    break;
	                case RefBool:
	                    msg += "<boolR>" + arguments[i].value + "</boolR>";
	                    break;
	                case DateTime:
	                case Date:
	                    msg += "<dateTime>" + arguments[i].value + "</dateTime>";
	                    break;
	                case RefDateTime:
	                case RefDate:
	                    msg += "<dateTimeR>" + arguments[i].value + "</dateTimeR>";
	                    break;
	                case Array: //only 1 dimension allowed
	                    msg += "<array>";
	                    for (var j = 0; j < arguments[i].length; j++) msg += "<a><![CDATA[" + arguments[i][j] + "]]></a>";
	                    msg += "</array>";
	                    break;
	                case RefArray: //only 1 dimension allowed
	                    msg += "<arrayR>";
	                    for (var j = 0; j < arguments[i].length; j++) msg += "<a><![CDATA[" + arguments[i][j] + "]]></a>";
	                    msg += "</arrayR>";
	                    break;
	                case XML:
	                    msg += "<xml>" + arguments[i].value + "</xml>";
	                    break;
	                case RefXML:
	                    msg += "<xmlR>" + arguments[i].value + "</xmlR>";
	                    break;
	                case AvoidRemote:
	                    break;
	                default:
	                    alert("Invalid type: " + arguments[i].constructor + ". Koristite tipove: Int, Double, String, itd. Pozivaju se npr. putem 'new Int(3)'.");
	                    break;
	            }
	        }
	    }
	    msg += "</msg>";
	    if (this.usePost)
	        http.open("POST", "ClientServer.ashx", async);
	    else
	        http.open("GET", "ClientServer.ashx?" + escape(msg), async);
	    http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	    http.send(msg);
	    if (!async) {
	        if (http.status != 200) showError("HTTPRequest.status=" + http.status);
	        if (http.responseText.length == 0) showError("HTTPRequest.responseText==''");
	        getRef(http, origArguments);
	        return http.responseXML;
	    }
	};
}

function intermed(http,callBackFunction,origArguments){
	if(getRef(http,origArguments)) callBackFunction(http,origArguments);
}

function getRef(http,origArguments){
	var dbg=0;
	try{
	    var status = null; 
	    if (selectSingleNodeIEF(http.responseXML, "/msg/@status") != null) status = selectSingleNodeIEF(http.responseXML, "/msg/@status").firstChild.nodeValue;
	    switch (status) {
	        case "OK": dbg = 10;
	            for (var i = 0; i < origArguments.length; i++) {
	                if (origArguments[i] != null)
	                    switch (origArguments[i].constructor) {
	                    case RefString: case RefInt: case RefBool: case RefDateTime: case RefDate:
	                        dbg = 20;
	                        origArguments[i].value = selectSingleNodeIEF(http.responseXML, "/msg/rtn/r" + i).firstChild.nodeValue;
	                        break;
	                    case RefArray:
	                        throw "Not implemented";
	                    case RefXML:
	                        dbg = 30;
	                        origArguments[i].value = serializeXml(selectSingleNodeIEF(http.responseXML, "/msg/rtn/r" + i));
	                        break;
	                }
	            } 
	            return true;
	        case "WR":
	            showError(selectSingleNodeIEF(http.responseXML, "/msg/message").firstChild.nodeValue, false, true);
	            return false;
	        case "ER": 
	            showError(selectSingleNodeIEF(http.responseXML, "/msg/message").firstChild.nodeValue, false, false);
	            return false;
	        default:
	            dbg = 40;
	            showError("Error in response, XMLHTTPRequest.responseText="+http.responseText, false, false);
	            return false;
	    }
	}catch(e){showError(e);}
}
function RefInt(value){this.value=value;}
function Int(value){this.value=value;}
function RefDouble(value){this.value=value;}
function Double(value){this.value=value;}
function RefString(value){this.value=value;}
function RefBool(value){this.value=value;}
function Bool(value){this.value=value;}
function RefDate(value){this.value=value;}
function RefDateTime(value){this.value=value;}
function DateTime(value){this.value=value;}
function RefXML(value){this.value=value;}
function XML(value){this.value=value;}
function RefArray(value){throw "Not implemented";}
function AvoidRemote(value){this.value=value;}
function createType(typeName,value){
	switch(typeName){
		case "intR":return new RefInt(value);break;
		case "int":case "varInt":return new Int(value);break;
		case "doubleR":return new RefDouble(value);break;
		case "double":return new Double(value);break;
		case "stringR":return new RefString(value);break;
		case "string":case "varString":return new String(value);break;
		case "boolR":return new RefBool(value);break;
		case "bool":return new Bool(value);break;
		case "date":return new Date(value);break;
		case "dateR":return new RefDate(value);break;
		case "dateTimeR":return new RefDateTime(value);break;
		case "dateTime":return new DateTime(value);break;
		case "xmlR":return new RefXML(value);break;
		case "xml":return new XML(value);break;
		case "array":return new Array(value);break;
		case "arrayR":return new RefArray(value);break;
		case "avoid":return new AvoidRemote(value);break;
	}
}
