function createajaxObjectRequestObject() {
    var httpRequest = null;

    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
        httpRequest = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) { // IE
        try {
            httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e) {
            try {
                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e) {}
        }
    }

    if (!httpRequest) {
        ajaxError('Could not initiate AJAX object');
        return false;
    }

    return httpRequest;
}

function ajaxRequestDisplay(url, httpRequestMethod, requestParameter, displayId)
{
    callbackFunc = function(response, callbackArg) {
            document.getElementById(displayId).innerHTML = response;
            document.getElementById(displayId).style.display = 'block';
        };
    ajaxRequest(url, httpRequestMethod, requestParameter, false, callbackFunc);
}

function ajaxRequest(url, httpRequestMethod, requestParameter, xml, callbackFunc, callbackArg) {
    if(httpRequestMethod!='GET' && httpRequestMethod!='POST')
    {
        ajaxError('Bad request method ['+httpRequestMethod+']');
        return false;
    }

    ajaxObject = createajaxObjectRequestObject();

    var response = false;
    ajaxObject.open(httpRequestMethod, url, true);
    ajaxObject.onreadystatechange = function() {
        try {
            if (ajaxObject.readyState == 4)
            {
                if (ajaxObject.status == 200)
                {
                    if(xml)
                    {
                        try
                        {
                            response = ajaxObject.responseXML;

                            if(!ajaxValidateXmlResponse(response))
                                return false;

                            xmlCleanWhitespace(response);
                        }
                        catch (e)
                        {
                            ajaxError(null, null, e);
                            return false;
                        }
                    }
                    else
                    {
                        try
                        {
                            response = ajaxObject.responseText;
                        }
                        catch (e)
                        {
                            ajaxError(null, null, e);
                            return false;
                        }
                    }

                    if(callbackFunc)
                        callbackFunc(response, callbackArg);
                }
                else
                {
                    ajaxError('Server returned status code ['+ajaxObject.status+' '+ajaxObject.statusText+']');
                    return false;
                }
            }
        }
        catch (e) {
            ajaxError(null, null, e);
            return false;
        }
    };

    postString = null;
    if (httpRequestMethod == 'POST') {
        ajaxObject.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

        if(requestParameter)
        {
            for (i in requestParameter)
            {
                if(postString)
                    postString += '&';
                if(postString)
                    postString += encodeURIComponent( requestParameter[i][0] ) + '=' + encodeURIComponent( requestParameter[i][1] );
                else
                    postString  = encodeURIComponent( requestParameter[i][0] ) + '=' + encodeURIComponent( requestParameter[i][1] );
            }
        }
    }
    ajaxObject.send(postString);

    return response;
}

function ajaxError(errMsg, errCode, techDescr) {
    var alertMsg = 'AJAX error.';
    if(errCode)
        alertMsg += ' Error code: '+errCode+'.';

    if(errMsg)
        alertMsg += ' '+errMsg+'.';
    else
        alertMsg += ' Unknown description.';

    if( (dev||admin) && techDescr)
        alertMsg += ' Tech: '+techDescr+'.';

    alert(alertMsg);
}

function ajaxValidateXmlResponse(xmlResponse) {
    try {
        if(xmlResponse.documentElement.nodeName=='parsererror') //For Firefox
        {
            ajaxError('XML parse error');
            return false;
        }
    }
    catch (e) {
        ajaxError('XML parse error', null, e);
        return false;
    }

    try {
        if(xmlResponse.documentElement.nodeName == 'error')
        {
            var errorMessage;
            var errorCode;

            errorCode     = xmlResponse.documentElement.getElementsByTagName('code')[0].firstChild.nodeValue;

            errorMessages = xmlResponse.documentElement.getElementsByTagName('message');
            if(errorMessages.length > 0)
                errorMessage = errorMessages[0].firstChild.nodeValue;

            if(!errorMessage)
                errorMessage = 'Backend responded with error';

            ajaxError(errorMessage, errorCode);
            return false;
        }
    }
    catch (e) {
        ajaxError('Unknown XML parse error', null, e);
        return false;
    }

    return true;
}

function xmlCleanWhitespace(root) {
    var notWhitespace = /[^\t\n\r ]/; //   /\S/
    for (var i=0; i < root.childNodes.length; i++) {
        var childNode = root.childNodes[i];
        if ((childNode.nodeType == 3)&&(!notWhitespace.test(childNode.nodeValue))) {
            // that is, if it's a whitespace text root
            root.removeChild(root.childNodes[i]);
            i--;
        }
        if ( childNode.nodeType == 1) {
            // elements can have text child nodes of their own
            xmlCleanWhitespace(childNode);
        }
    }
}
