/**
 * vytvori instanci http_request
 *
 */
function AJAXmakeInstance () {
    var http_request = false;
    if (window.XMLHttpRequest) { // Mozilla, Safari,...
       http_request = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
       try {
          http_request = new ActiveXObject("Msxml2.XMLHTTP");
       } catch (e) {
          try {
             http_request = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (e) {}
       }
    }
    if (!http_request) {
       alert('AJAX unit: Cannot create XMLHTTP instance');
       return false;
    }
    return http_request;
}

/**
 * metoda, ktera nacte data z adresy url a vrati ke zpracovani
 * ukazka pouziti: AJAXrequest("POST","get.php?test="+encodeURIComponent("hodnota/hodnota2"), true, "name_post_variable1="+encodeURIComponent("aaa/bbb")+"&"+"name_post_variable2="+encodeURIComponent("lib.text...ccc&ddd?bbb"), spracuj_data, "responseText");
 * 
 * @param method            metoda pozadavku, muze byt "GET", "POST", "HEAD", "PUT", "DELETE" a dalsi, testovano pouze "POST" a "GET"
 * @param url               url adresa pozadavku, muze byt http, ftp, file apod.
 * @param async             typ prenosu, muze byt asynchronni, pokud async=true, nebo synchronni, pokud async=false. V pripade asynchronniho zpracovani
 *                          je treba vyplnit nazev funkce $callbackFunction, ktera zpracuje vysledek. Funkce se ukonci pred dokoncenim prenosu a nevrati nic.
 *                          Po skonceni prenosu aktivuje JAVASCRIPT funkci callbackFunction, ktera dostane vstupni parametr podle returnType.
 *                          V pripade synchronniho zpracovani funkce ceka, dokud prenos neskonci a pak vrati vysledek ve formatu returnType.
 * @param postData         seznam POST parametru, oddeleny znakem "&", hodnoty je treba zakodovat funkci urlencode() v PHP, nebo encodeURIComponent() v JAVASCRIPTU. Hodnota postData muze vypadat napriklad takto post1=a%26b%26c&post2=a%26b%26c.
 * @param callbackFunction  nazev JAVASCRIPT funkce, ktera zpracuje vysledek v pripade pouziti asynchronniho prenosu
 * @param callbackParams    nazev promenne, ve ktere jsou ulozeny parametry pro callback funkci
 * @param returnType        udava, jaky format maji mit prijata data, muze byt "text", "xml", "body", "object_http_request"
 * @param overrideMimeType  aktivni pouze u GECKO, lze nastavit, jaky typ maji mit vstupni data. Lze tim predejit chybovemu hlaseni, pokud data nejsou validni XML. V tom pripade se doporucuje nastavit 'text/html' 
 * @param userName          NEIMPLEMENTOVANO, ma byt uzivatelske jmeno v pripade zabezpeceneho prenosu
 * @param password          NEIMPLEMENTOVANO
 * @param errorCounter      pocitac poctu chyb, pokud se stane trikrat po sobe chyba, zavola se errorFunction
 * @param responseTag       pokud je vystup XML, kontroluje se pristomnost tohoto tagu
 * @param timeout           timeout v sekundach
 * @param maxErrors         kolikrat se pokusi ajax o request, nez napise chybovou hlasku. 0=ihned napise chybu, 1=zkusi jeste jednou ...
 * @param waitOnError       jen u asynchronniho prenosu, jak dlouho cekat, pred dalsim volanim request, kdyz vznikne chyba. U synchronniho prenosu se novy pozadavek spusti ihned
 *
 * @return mixed     JAVASCRIPT kod, ktery umistime do html stranky
 */

function AJAXrequest2(url, params) {
        if (typeof params == 'undefined') {
            var params = {};
        }
        if (typeof params.method == 'undefined') {
            params.method = 'GET';
        }
        if (typeof params.returnType == 'undefined') {
            params.returnType = '';
        }
        if (typeof params.async == 'undefined') {
            params.async = false;
        }
        if (typeof params.maxErrors == 'undefined') {
            params.maxErrors = 0;
        }
        if (typeof params.waitOnError == 'undefined') {
            // 10 sec
            params.waitOnError = 10 * 1000;
        }
        if (typeof params.errorCounter == 'undefined') {
            params.errorCounter = 0;
        }
        if (typeof params.responseTag == 'undefined') {
            params.responseTag = 'response';
        }
        if (typeof params.timeout == 'undefined') {
            params.timeout = 1000;
        }

        var http_request = AJAXmakeInstance();
        if (http_request.overrideMimeType && params.overrideMimeType) {
            http_request.overrideMimeType(params.overrideMimeType);
        }

        if (params.async==true && typeof(params.callbackFunction)=='function') {
            http_request.onreadystatechange = function() {
                try {
                    if (http_request.readyState == 4) {
                        if (http_request.status == 200) {
                            if (params.testMode) {
                                report.document.write("<xmp>async req, status: 200"+"\nresponseText:"+http_request.responseText+"\n\n</xmp>");
                            }
                            if (params.returnType=='text') {
                                params.callbackFunction(http_request.responseText);
                            } else if (params.returnType=='xml') {
                                //kontrola, jestli jsme obdrzeli spravne XML
                                if (http_request.responseXML && typeof http_request.responseXML.getElementsByTagName(params.responseTag).item(0) == 'object') {
                                    params.callbackFunction(http_request.responseXML, params.callbackParams);
                                } else {
                                    if (params.testMode) {
                                        report.document.write("<xmp>async req error, response is not xml, status: "+http_request.status+"\n</xmp>");
                                    }
                                    throw "no response";
                                }
                            } else if (params.returnType=='body') {
                                params.callbackFunction(http_request.responseBody, params.callbackParams);
                            } else {
                                params.callbackFunction(http_request, params.callbackParams);
                            }
                        } else {
                            if (params.testMode) {
                                report.document.write("<xmp>async req error, status: "+http_request.status+"\n</xmp>");
                            }
                            throw "no response";
                        }
                    }
                } catch(e) {
                    // pokud pocet chyb neprekrocil maxErrors, pusti se ajax request znova
                    if (params.errorCounter<params.maxErrors) {
                        params.errorCounter++;
                        if (params.testMode) {
                            report.document.write("<xmp>error n. "+params.errorCounter.toString()+", params.maxErrors: "+params.maxErrors.toString()+", setTimeout "+params.waitOnError.toString()+"</xmp>");
                        }
                        // spustit dotaz znovu po urcite dobe
                        window.setTimeout(function() { AJAXrequest2(url, params);}, params.waitOnError);
                    } else {
                        if (params.errorFunction) {
                            params.errorFunction(params.errorFunctionParams);
                        } else {
                            alert('AJAX Error: no response');
                        }
                    }
                }
            }
        }

        http_request.open(params.method, url, params.async);

        // http_request.setTimeouts(timeout, timeout, timeout, timeout);
        // timeout (od IE8)
        // @todo: otestovat jestli to funguje a omezit jen na IE8
        // http_request.timeout = params.timeout;

        if (params.method=='POST') {
            http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        }
        http_request.send(params.postData);
        if (params.testMode) {
            report.document.write("<xmp>http_request.send\n"+url+'&'+params.postData+"\n\n</xmp>");
        }
        if (!params.async) {
            try {
                if (http_request.status == 200) {
                    if (params.testMode) {
                        report.document.write("<xmp>sync req, status: 200"+"\nresponseText:"+http_request.responseText+"\n\n</xmp>");
                    }
                    if (params.returnType=='text') {
                        if (typeof(params.callbackFunction)=='function') {
                            params.callbackFunction(http_request.responseText, params.callbackParams);
                        }
                        return http_request.responseText;
                    } else if (params.returnType=='xml') {
                        //kontrola, jestli jsme obdrzeli spravne XML
                        if (http_request.responseXML && typeof http_request.responseXML.getElementsByTagName(params.responseTag).item(0) == 'object') {
                            if (typeof(params.callbackFunction)=='function') {
                                params.callbackFunction(http_request.responseXML, params.callbackParams);
                            }
                            return http_request.responseXML;
                        } else {
                            if (params.testMode) {
                                report.document.write("<xmp>sync req error, response is not xml, status: "+http_request.status+"\n</xmp>");
                            }
                            throw "no response";
                        }
                    } else if (params.returnType == 'body') {
                        if (typeof(params.callbackFunction)=='function') {
                            params.callbackFunction(http_request.responseBody, params.callbackParams);
                        }
                        return http_request.responseBody;
                    } else {
                        if (typeof(params.callbackFunction)=='function') {
                            params.callbackFunction(http_request, params.callbackParams);
                        }
                        return http_request;
                    }
                } else {
                    if (params.testMode) {
                        report.document.write("<xmp>sync req error, status: "+http_request.status+"\n</xmp>");
                    }
                    throw "no response";
                }
            } catch (e) {
                // pokud pocet chyb neprekrocil params.maxErrors, pusti se ajax request znova
                if (params.errorCounter<params.maxErrors) {
                    params.errorCounter++;
                    //  spustit dotaz znovu
                    AJAXrequest2(url, params);
                } else {
                    if (params.errorFunction) {
                        params.errorFunction(params.errorFunctionParams);
                    } else {
                        alert('AJAX Error: no response');
                    }
                    return false;
                }
            }
        } else {
            // v pripade ze se jedna o asynchronni prenost, tak jen vratim true, ze odeslani dotazu probehlo v poradku
            return true;
        }
}

function AJAXrequest(method, url, async, postData, callbackFunction, callbackParams, errorFunction, errorFunctionParams, returnType, overrideMimeType, userName, password, testMode, errorCounter, responseTag, timeout) {
    var params = {
        'method':method,
        'async':async,
        'postData':postData,
        'callbackFunction':callbackFunction,
        'callbackParams':callbackParams,
        'errorFunction':errorFunction,
        'errorFunctionParams':errorFunctionParams,
        'returnType':returnType,
        'overrideMimeType':overrideMimeType,
        'userName':userName,
        'password':password,
        'testMode':testMode,
        'errorCounter':errorCounter,
        'responseTag':responseTag,
        'timeout':timeout
    }
    return AJAXrequest2(url, params);
}