// -------------------------------------------------------------------------------------------------
//      ISIS JavaScript Framework by Marius S., www.mariaus.info
// -------------------------------------------------------------------------------------------------

// CONSTANTS
window.JSConsts = {

    'animation': {
        'fast': 10,
        'medium': 25,
        'slow': 50
    },

    'position': {
        'top': 1,
        'right': 2,
        'bottom': 3,
        'left': 4,
        'topLeft': 5,
        'topRight': 6,
        'righTtop': 7,
        'rightBottom': 8,
        'bottomRight': 9,
        'bottomLeft': 10,
        'leftBottom': 11,
        'leftTop': 12,
        'mouse': 13
    },

    'ajaxError': {
        'connectionError': 1,   // connection status != 200
        'emptyResult': 2,       // isis request returned empty string
        'transactionError': 3,  // isis request returned ERR:XXX
        'evalError': 4,         // unable to parse object, returned by isis request
        'operationError': 5,    // isis request returned operation error (pResult.error != 'no')
        'connectionTimeout': 6, // connection timeout
        'operationTimeout': 7   // transfer timeout
    }

};


// -------------------------------------------------------------------------------------------------
//      JSIsisAnimator and JSIsisAnimatorValue classes
// -------------------------------------------------------------------------------------------------

/*
    A single value to be animated with JSIsisAnimator

    pStart - starting point (integer)
    pEnd - ending point (integer)
    pId - value id (eg. alpha, width etc.)
*/
function JSIsisAnimatorValue(pStart, pEnd, pId)
{
    this.startValue = pStart;
    this.endValue = pEnd;
    this.currentValue = pStart;
    this.valueId = pId;
}

/*
    Animator for multiple values

    pId - animation id (eg. div1, table etc.)
*/
function JSIsisAnimator(pId)
{
    this.values = [];               // Animation values
    this.onEnd = null;              // An event, triggered after animation ends
    this.onAnimate = null;          // An event, triggered for each calculated value
    this.animId = pId;              // An animation identifier
    this.animInt = null;            // Animation interval

    this.stop = function()
    {
        if (this.animInt)
        {
            clearInterval(this.animInt);
            this.animInt = null;
        }
    }

    /*
        Animates the values

        pSteps - animation step count
        pStrengt - animation speed ( 0 < x < 1 - ease out, x > 1 - ease in, 1 - linear)
    */
    this.animate = function(pSteps, pStrength)
    {
        if (this.animInt)
        {
            clearInterval(this.animInt);
            this.animInt = null;
        }

        var step = 1;

        if (pSteps < 1)
            return;

        if (pStrength < 0.1)
            pStremgth = 0.1;

        var anim = this;

        this.animInt = setInterval(
            function()
            {
                if (step > pSteps)
                {
                    anim.stop();

                    if (anim.onEnd)
                    {
                        try { anim.onEnd(this); } catch(e) {};
                    }
                }
                else
                {
                    for (var i = 0; i < anim.values.length; i++)
                    {
                        var val = anim.values[i];
                        var dt = val.endValue - val.startValue;
                        var curr = Math.ceil(val.startValue + (Math.pow(((1 / pSteps) * step), pStrength) * dt));
                        val.currentValue = curr;
                    }

                    step += 1;

                    if (anim.onAnimate)
                    {
                        try { anim.onAnimate(anim); } catch(e) {};
                    }
                }
            }
        , 10);
    }

    /*
        Adds a new value to animate

        pStart - starting point
        pEnd - ending point
        pId - value id (eg. width, alpha etc.)
    */
    this.addValue = function(pStart, pEnd, pId)
    {
        var val = new JSIsisAnimatorValue(pStart, pEnd, pId);
        this.values[this.values.length] = val;
    }

    /*
        Deletes all animation values
    */
    this.clearValues = function()
    {
        this.values = [];
    }

    /*
        Returns the current value for a specified value id

        pId - the value id
    */
    this.valueFor = function(pId)
    {
        for (var i = 0; i < this.values.length; i++)
            if (this.values[i].valueId == pId)
                return this.values[i].currentValue;

        return null;
    }
}

// -------------------------------------------------------------------------------------------------
//      JSIsisElement class
// -------------------------------------------------------------------------------------------------


function JSIsisElement()
{
    this.elementArray = [];

    /*
        Checks if a value is null or undefined

        pValue - a value to check
    */
    this.isUndefined = function(pValue)
    {
        return (typeof pValue == 'undefined' || pValue == null);
    }

    /*
        Returns an element object by its id or an element reference

        pObj - element's id or an actual element object
    */
    this.element = function(pObj)
    {
        var tmp = [];

        if (typeof pObj != 'object')
        {
            var obj = document.getElementById(pObj);

            if (obj)
                tmp[tmp.length] = obj;
        }
        else
            tmp[tmp.length] = pObj;

        this.elementArray = tmp;
        return this;
    }

    /*
        Hides object(s)
    */
    this.hide = function()
    {
        for (var i = 0; i < this.elementArray.length; i++)
            if (this.elementArray[i])
                this.elementArray[i].style.display = 'none';

        return this;
    }

    /*
        Shows object(s)
    */
    this.show = function()
    {
        for (var i = 0; i < this.elementArray.length; i++)
            this.elementArray[i].style.display = 'block';

        return this;
    }

    /*
        Retrieves the parent node
    */
    this.parent = function()
    {
        if (this.elementArray.length > 0)
            return this.elementArray[0].parentNode;
        else
            return null;
    }

    /*
        Returns parent node as an element instead of an HTML object
    */
    this.parentElement = function()
    {
        if (this.elementArray.length < 1)
            return null;

        var elm = this.elementArray[0].parentNode;

        if (elm)
            return $element(elm);
        else
            return null;
    }

    /*
        Disables object(s)
    */
    this.disable = function()
    {
        if (this.elementArray.length > 0)
        {
            for (var i = 0; i < this.elementArray.length; i++)
                this.elementArray[i].disabled = true;

            return this;
        }
        else
            return this;
    }

    /*
        Enables object(s)
    */
    this.enable = function()
    {
        if (this.elementArray.length > 0)
        {
            for (var i = 0; i < this.elementArray.length; i++)
                this.elementArray[i].disabled = false;

            return this;
        }
        else
            return this;
    }

    /*
        Returns the first object in elements array
    */
    this.obj = function()
    {
        if (this.elementArray.length > 0)
            return this.elementArray[0];
        else
            return null;
    }

    /*
        Returns the size of the element
    */
    this.size = function()
    {
        if (this.elementArray.length < 1 || !this.elementArray[0])
            return this;

        var ww = 0;
        var hh = 0;
        ww = this.elementArray[0].offsetWidth;
        hh = this.elementArray[0].offsetHeight;
        return {'w': ww, 'h': hh};
    }

    /*
        Returns element's position
    */
    this.pos = function()
    {
        if (this.elementArray.length < 1 || !this.elementArray[0])
            return this;

        var x = 0;
        var y = 0;
        var obj = this.elementArray[0];

        if (obj.offsetParent) {
            do {
                x += obj.offsetLeft;
                y += obj.offsetTop;
            } while (obj = obj.offsetParent);
        }

        return {'x': x, 'y': y};
    }

    /*
        Sets the size of an element

        pWidth - the new width (if null, width will not be changed)
        pHeight - the new height (if null, height will not be changed)
        pUnits - measurement units (default: 'px')
    */
    this.setSize = function(pWidth, pHeight, pUnits)
    {
        if (this.isUndefined(pUnits))
            pUnits = 'px';

        if (this.elementArray.length < 1 || !this.elementArray[0])
            return this;

        if(!this.isUndefined(pWidth))
            this.elementArray[0].style.width = pWidth + pUnits;

        if (!this.isUndefined(pHeight))
            this.elementArray[0].style.height = pHeight + pUnits;

        return this;
    }

    /*
        Sets the position of an element

        pX - the new x coordinate (if null, x will not be changed)
        pHeight - the new y coordinate (if null, y will not be changed)
        pUnits - measurement units (default: 'px')
    */
    this.setPos = function(pX, pY, pUnits)
    {
        if (this.isUndefined(pUnits))
            pUnits = 'px';

        if (this.elementArray.length < 1 || !this.elementArray[0])
            return this;

        if(!this.isUndefined(pX))
            this.elementArray[0].style.left = pX + pUnits;

        if (!this.isUndefined(pY))
            this.elementArray[0].style.top = pY + pUnits;

        return this;
    }

    /*
        Sets the object transparency

        pAlpha - alpha value (0 - 100)
    */
    this.setAlpha = function(pAlpha)
    {
        if (this.elementArray.length < 1 || !this.elementArray[0])
            return this;

        this.elementArray[0].style.opacity = pAlpha / 100;
        this.elementArray[0].style.filter = 'alpha(opacity=' + pAlpha + ')';
        return this;
    }

    /*
        Checks if an element exists
    */
    this.exists = function()
    {
        if (this.elementArray.length < 1)
            return false;
        else
            return true;
    }

    /*
        Destroys the element
    */
    this.free = function()
    {
        if (this.elementArray.length < 1)
            return;

        if (this.elementArray[0].parentNode)
            this.elementArray[0].parentNode.removeChild(this.elementArray[0]);
    }

    /*
        Assigns an object instead of finding it by id

        pObject - object to assign to
    */
    this.assign = function(pObject)
    {
        this.elementArray = [];
        this.elementArray[this.elementArray.length] = pObject;
        return this;
    }

    /*
        Sets the content of the element (html)

        pContent - html to set
        pMethod - a way to set it (replace, add, prefix)
    */
    this.setContent = function(pContent, pMethod)
    {
        if (this.elementArray.length < 1)
            return this;

        for (var i = 0; i < this.elementArray.length; i++)
            if (this.elementArray[i])
            {
                if (pMethod == 'add')
                    this.elementArray[i].innerHTML += pContent;
                else if (pMethod == 'prefix')
                    this.elementArray[i].innerHTML = pContent + this.elementArray[i].innerHTML;
                else
                    this.elementArray[i].innerHTML = pContent;
            }

        return this;
    }

    /*
        Returns the content of the element (html)
    */
    this.content = function()
    {
        if (this.elementArray.length < 1)
            return null;

        return this.elementArray[0].innerHTML;
    }

    /*
        Sets the value of the element

        pValue - value to set
        pMethod - a way to set it (replace, add, prefix)
    */
    this.setValue = function(pValue, pMethod)
    {
        if (this.elementArray.length < 1)
            return this;

        for (var i = 0; i < this.elementArray.length; i++)
            if (this.elementArray[i])
            {
                if (pMethod == 'add')
                    this.elementArray[i].value += pValue;
                else if (pMethod == 'prefix')
                    this.elementArray[i].value = pValue + this.elementArray[i].value;
                else
                    this.elementArray[i].value = pValue;
            }

        return this;
    }

    /*
        Returns the value of the element
    */
    this.value = function()
    {
        if (this.elementArray.length < 1 || ! this.elementArray[0])
            return null;
        return this.elementArray[0].value;
    }

    /*
        Toggles the visibility of the element(s)
    */
    this.toggleDisplay = function()
    {
        if (this.elementArray.length < 1)
            return this;

        for (var i = 0; i < this.elementArray.length; i++)
        {
            if (this.elementArray[i].style.display != 'none')
                this.elementArray[i].style.display = 'none';
            else
                this.elementArray[i].style.display = 'block';
        }

        return this;
    }


}


// -------------------------------------------------------------------------------------------------
//      JSIsis class (global $.() accessor)
// -------------------------------------------------------------------------------------------------


/*
    JSIsis framework
*/
(function (){

var JSIsis =
{

    /*
        Checks if a value is null or undefined

        pValue - a value to check
    */
    isUndefined: function(pValue)
    {
        return (typeof pValue == 'undefined' || pValue == null);
    },

    /*
        Returns the first parameter that is defined and not null
    */
    coalesce: function()
    {
        for (var i = 0; i < arguments.length; i++)
            if (!$.isUndefined(arguments[i]))
                return arguments[i];

        return null;
    },

    /*
        Returns the size of the client window (viewport)
    */
    viewSize: function()
    {
        var ww = 0;
	    var hw = 0;

	    //IE
	    if(!window.innerWidth)
	    {
		    //strict mode
		    if(!(document.documentElement.clientWidth == 0))
		    {
			    ww = document.documentElement.clientWidth;
			    hh = document.documentElement.clientHeight;
		    }
		    //quirks mode
		    else
		    {
			    ww = document.body.clientWidth;
			    hh = document.body.clientHeight;
		    }
	    }
	    //w3c
	    else
	    {
		    ww = window.innerWidth;
		    hh = window.innerHeight;
	    }

	    return {'w':ww, 'h':hh};
    },

    view: function()
    {
	    var _x = 0;
	    var _y = 0;
	    var offsetX = 0;
	    var offsetY = 0;

	    //IE
	    if(!window.pageYOffset)
	    {
		    //strict mode
		    if(!(document.documentElement.scrollTop == 0))
		    {
			    offsetY = document.documentElement.scrollTop;
			    offsetX = document.documentElement.scrollLeft;
		    }
		    //quirks mode
		    else
		    {
			    offsetY = document.body.scrollTop;
			    offsetX = document.body.scrollLeft;
		    }
	    }
	    //w3c
	    else
	    {
		    offsetX = window.pageXOffset;
		    offsetY = window.pageYOffset;
	    }

        var viewSz = this.viewSize();
	    _x = ((viewSz.w) / 2) + offsetX;
	    _y = ((viewSz.h) / 2) + offsetY;

        var resSz = {'w': viewSz.w, 'h': viewSz.h};
        var resCenter = {'x': _x, 'y': _y};
        var resPos = {'x': offsetX, 'y': offsetY};
	    return{'pos': resPos, 'size': resSz, 'center': resCenter};
    },

    /*
        Returns the center point of the current viewport
    */
    viewCenter: function()
    {
	    var _x = 0;
	    var _y = 0;
	    var offsetX = 0;
	    var offsetY = 0;

	    //IE
	    if(!window.pageYOffset)
	    {
		    //strict mode
		    if(!(document.documentElement.scrollTop == 0))
		    {
			    offsetY = document.documentElement.scrollTop;
			    offsetX = document.documentElement.scrollLeft;
		    }
		    //quirks mode
		    else
		    {
			    offsetY = document.body.scrollTop;
			    offsetX = document.body.scrollLeft;
		    }
	    }
	    //w3c
	    else
	    {
		    offsetX = window.pageXOffset;
		    offsetY = window.pageYOffset;
	    }

	    _x = ((this.viewSize().w) / 2) + offsetX;
	    _y = ((this.viewSize().h) / 2) + offsetY;
	    return{'x':_x, 'y':_y};
    },

    /*
        Returns the size of the Whole document (page)
    */
    docSize: function()
    {
        var ww = 0;
        var hh = 0;

        hh = Math.max(
        Math.max(document.body.scrollHeight, document.documentElement.scrollHeight),
        Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
        Math.max(document.body.clientHeight, document.documentElement.clientHeight));

        ww = Math.max(
        Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
        Math.max(document.body.offsetWidth, document.documentElement.offsetWidth),
        Math.max(document.body.clientWidth, document.documentElement.clientWidth));

	    return {w:ww, h:hh};
    },

    /*
        Get the mouse coordinates in a window

        pEvent - an "event" var, passed by onmousemove event
    */
    mousePos: function(pEvent) {
         var posx = 0;
         var posy = 0;
         var e = pEvent;

         if (!e)
            e = window.event || window.Event;

         if (e.pageX || e.pageY)
         {
              posx = e.pageX;
              posy = e.pageY;
         }
         else if (e.clientX || e.clientY)
         {
              posx = e.clientX + document.body.scrollLeft
                               + document.documentElement.scrollLeft;
              posy = e.clientY + document.body.scrollTop
                               + document.documentElement.scrollTop;
         }

         return {'x':posx,'y':posy}
    },

    /*
        Get the width and height of a specified text

        pText - the text to calculate metrics for
        pClass - the class that defines the font metrics to use in calculations.
                 This class should only describe font specifications like weight,
                 decorations, family and size. It cannot contain
    */
    textSize: function(pText, pClass)
    {
        // Try to retrieve a temporary canvas for the measurement
        // calculations. We'll need to create it if it doesn't exist yet.
        var obj = document.getElementById('JSIsisContentMeasurement');

        if (!obj)
        {
            obj = document.createElement('div');

            if (!this.isUndefined(pClass))
                obj.className = pClass;

            obj.setAttribute('id', 'JSIsisContentMeasurement');
            obj.style.position = 'absolute';
            obj.style.visibility = 'hidden';
            obj.style.height = 'auto';
            obj.style.width = 'auto';
            obj.style.padding = '0';
            obj.innerHTML = pText;
            document.body.appendChild(obj);
        }
        else
        {
            if (!this.isUndefined(pClass))
                obj.className = pClass;
        }
        var sz = $element('JSIsisContentMeasurement').size();
        return sz;
    },

    /*
        Returns the element under the mouse

        pEvent - window event
    */
    elementUnderMouse: function(pEvent)
    {
        if (!pEvent)
            pEvent = window.event;

        var theElement = null;
        var coordX = pEvent.clientX;
        var coordY = pEvent.clientY;

        // Safari and opera need this fix to work correctly
        if (window.opera || (navigator.vendor && navigator.vendor.substr (0, 5) == "Apple"))
        {
            coordX = pEvent.pageX;
            coordY = pEvent.pageY;
        }

        theElement = document.elementFromPoint(coordX, coordY);
        return theElement;
    }


}

if(!window.$){window.$=JSIsis;}

})();


// -------------------------------------------------------------------------------------------------
//      IsisAjax class
// -------------------------------------------------------------------------------------------------


/*
    Mini AJAX class
*/
function IsisAjax()
{

    /*
        Returns XMLHttp object for ajax requests
    */
    this.getHttpObj = function()
    {
        var xmlHttp = null;
        // let's try firefox, opera 8+ and Safari
        try
        {
            xmlHttp = new XMLHttpRequest();
        }
        catch(e)
        {
            // all the rest stuff for IE ...
            try
            {
                xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch(e)
            {
                try
                {
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch(e)
                {
                    try
                    {
                        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                    }
                    catch(e) {}
                }
            }
        }
        return xmlHttp;
    }


    this.conn = this.getHttpObj();              // The connection object
    this.paramArray = [];                       // Parameter array
    this.lastResponse = null;                   // For debug purposes
    this.connTimeoutValue = 300;                // Connection timeout value in seconds
    this.opTimeoutValue = 300;                  // Operation timeout value in seconds
    this.debugMode = false;                     // Debug mode toggle
    this.connTimeout = null;
    this.opTimeout = null;
    this.onStart = null;                        // Event, triggered before the connection is established. Params:
                                                // (string)pUrl

    this.onEnd = null;                          // Event, triggered after connection has ended. Params:
                                                // (string)pResult,
                                                // (bool)pError,
                                                // (string)pErrorMsg

    this.onEndAdvanced = null;                  // Event, triggered after connection has ended. This event is Isis protocol
                                                // specific. Params:
                                                // (object|null)pResult,
                                                // (JSConst.ajaxError)pError,
                                                // (string)pErrorMsg.
                                                // In this case, pResult is a parsed object instead of a simple
                                                // string or null if an error occurs

    /*
        Adds a new http var to be sent via AJAX request
    */
    this.addVar = function(pName, pVal)
    {
        this.paramArray[this.paramArray.length] = {'name': pName, 'val': pVal};
    }

    /*
        Enables debug mode
    */
    this.enableDebugMode = function()
    {
        this.debugMode = true;
    }

    /*
        Disables debug mode
    */
    this.disableDebugMode = function()
    {
        this.debugMode = false;
    }

    /*
        Sets the debug mode

        pEnabled - enabled flag
    */
    this.setDebugMode = function(pEnabled)
    {
        this.debugMode = pEnabled;
    }

    /*
        Sets the timeout values

        pConnectionTimeout - time in seconds the connection has to be made in
        pOperationTimeout - time in seconds the transfer must complete in
    */
    this.setTimeout = function(pConnectionTimeout, pOperationTimeout)
    {
        if (!$.isUndefined(pConnectionTimeout))
            this.connTimeoutValue = pConnectionTimeout;

        if (!$.isUndefined(pOperationTimeout))
            this.opTimeoutValue = pOperationTimeout;
    }

    /*
        Adds a field with a specified name to be sent via AJAX request

        pName - the name of the field to send
    */
    this.addField = function(pName)
    {
        var arr = document.getElementsByName(pName);

        if (!arr)
            return false;

        if (arr.length < 1)
            return false;

        for (var i = 0; i < arr.length; i++)
        {

            var node_type = String.prototype.toLowerCase.apply(arr[i].type);
            var node_tag = String.prototype.toLowerCase.apply(arr[i].tagName);

            // text, hidden input or textarea
            if (node_type == 'text' || node_type == 'hidden' || node_tag == 'textarea' || node_type == 'password')
            {
                this.addVar(pName, arr[i].value);
            }

            // select
            if (node_tag == 'select')
            {
                for (var k = 0; k < arr[i].options.length; k++)
                    if (arr[i].options[k].selected)
                        this.addVar(pName, arr[i].options[k].value);
            }

            // checkbox and radio button
            if (node_type == 'checkbox' || node_type == 'radio')
            {
                if (arr[i].checked)
                    this.addVar(pName, arr[i].value);
            }

        }

        return true;

    }

    /*
        Adds comma separated html field values to be sent via AJAX request

        pNames - comma separated field names
    */
    this.addFields = function(pNames)
    {
        var arr = pNames.split(',');

        if (!arr || arr.length < 1)
            return;

        for (var i = 0; i < arr.length; i++)
            this.addField(arr[i]);
    }

    /*
        Clears all http vars
    */
    this.clearVars = function()
    {
        this.paramArray = [];
    }

    /*
        Sends a GET request

        pUrl - target url
    */
    this.getUrl = function(pUrl)
    {
        if (!pUrl)
            return;

        var me = this;

        if (this.connTimeout)
            clearTimeout(this.connTimeout);

        if (this.opTimeout)
            clearTimeout(this.opTimeout);

        var opTimeoutFunction = function()
        {
            me.abort();

            if (me.onEnd)
                me.onEnd(null, true, 'Operation timeout');
            else if (me.onEndAdvanced)
                me.onEndAdvanced(null, JSConsts.ajaxError.operationTimeout, 'Operation timeout');
        }

        var connTimeoutFunction = function()
        {
            me.abort();

            if (me.onEnd)
                me.onEnd(null, true, 'Connection timeout');
            else if (me.onEndAdvanced)
                me.onEndAdvanced(null, JSConsts.ajaxError.connectionTimeout, 'Connection timeout');
        }

        this.opTimeout = setTimeout(opTimeoutFunction, this.opTimeoutValue * 1000);
        this.connTimeout = setTimeout(connTimeoutFunction, this.connTimeoutValue * 1000);

        var paramsLine = '';   // Url parameters

        for (var i = 0; i < this.paramArray.length; i++)
        {
            if (i == 0)
            {
                paramsLine += '?' + this.paramArray[i].name + '=' + encodeURIComponent(this.paramArray[i].val);
                firstParam = false;
            }
            else
            {
                paramsLine += '&' + this.paramArray[i].name + '=' + encodeURIComponent(this.paramArray[i].val);
            }
        }

        pUrl += paramsLine;

        if (this.onStart)
            this.onStart(pUrl);

        var conn = this.conn;
        conn.open('GET', pUrl, true);
        var fOnEnd = this.onEnd;
        var fOnEndAdvanced = this.onEndAdvanced;

        conn.onreadystatechange = function()
        {
           if (conn.readyState == 2)
            {
                if (me.connTimeout)
                    clearTimeout(me.connTimeout);
            }
            else if (conn.readyState == 4)
            {
                if (me.connTimeout)
                    clearTimeout(me.connTimeout);

                if (me.opTimeout)
                    clearTimeout(me.opTimeout);
                var pError = false;
                me.lastResponse = conn.responseText;

                if (conn.status != 200)
                    pError = true;

                // Standart connection end handler
                if (fOnEnd)
                    fOnEnd(conn.responseText, pError, 'HTTP status: ' + conn.status);

                // Advanced connection end handler
                else if (fOnEndAdvanced)
                {
                    pResult = conn.responseText;

                    // connection error
                    if (pError)
                        fOnEndAdvanced(null, JSConsts.ajaxError.connectionError, 'HTTP status: ' + conn.status);
                    // empty result
                    else if (!pResult)
                        fOnEndAdvanced(null, JSConsts.ajaxError.emptyResult, 'Request returned an empty string');
                    // transaction error
                    else if (pResult.indexOf('ERR:') == 0)
                        fOnEndAdvanced(null, JSConsts.ajaxError.transactionError, pResult);
                    else
                    {
                        var evalError = false;

                        try { pResult = eval(pResult); } catch (e) { evalError = true; }

                        // Evaluation error
                        if (evalError)
                        {
                            if (!me.debugMode)
                                fOnEndAdvanced(null, JSConsts.ajaxError.evalError, 'Unable to parse server response');
                            else
                                fOnEndAdvanced(null, JSConsts.ajaxError.evalError, 'Unable to parse server response:\n\n' +
                                               me.lastResponse);
                        }
                        // Operation error
                        else if (pResult.error != 'no')
                            fOnEndAdvanced(null, JSConsts.ajaxError.operationError, pResult.error);
                        else
                            fOnEndAdvanced(pResult, 0, '');
                    }
                }
            }
        }

        try
        {
            conn.send(null);
        }
        catch(err)
        {
            if (this.onEnd)
                this.onEnd('', true, err.message);
        }
    }

    /*
        Sends a POST request

        pUrl - target url
    */
    this.postUrl = function(pUrl)
    {
        if (!pUrl)
            return;

        var me = this;

        if (this.connTimeout)
            clearTimeout(this.connTimeout);

        if (this.opTimeout)
            clearTimeout(this.opTimeout);

        var opTimeoutFunction = function()
        {
            me.abort();

            if (me.onEnd)
                me.onEnd(null, true, 'Operation timeout');
            else if (me.onEndAdvanced)
                me.onEndAdvanced(null, JSConsts.ajaxError.operationTimeout, 'Operation timeout');
        }

        var connTimeoutFunction = function()
        {
            me.abort();

            if (me.onEnd)
                me.onEnd(null, true, 'Connection timeout');
            else if (me.onEndAdvanced)
                me.onEndAdvanced(null, JSConsts.ajaxError.connectionTimeout, 'Connection timeout');
        }

        this.opTimeout = setTimeout(opTimeoutFunction, this.opTimeoutValue * 1000);
        this.connTimeout = setTimeout(connTimeoutFunction, this.connTimeoutValue * 1000);

        var paramsLine = '';   // Url parameters

        for (var i = 0; i < this.paramArray.length; i++)
        {
            if (i == 0)
            {
                paramsLine += this.paramArray[i].name + '=' + encodeURIComponent(this.paramArray[i].val);
                firstParam = false;
            }
            else
            {
                paramsLine += '&' + this.paramArray[i].name + '=' + encodeURIComponent(this.paramArray[i].val);
            }
        }

        if (this.onStart)
            this.onStart(pUrl);

        var conn = this.conn;
        conn.open('POST', pUrl, true);
        conn.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        conn.setRequestHeader("Content-length", paramsLine.length);
        conn.setRequestHeader("Connection", "close");

        var fOnEnd = this.onEnd;
        var fOnEndAdvanced = this.onEndAdvanced;

        conn.onreadystatechange = function()
        {
            if (conn.readyState == 2)
            {
                if (me.connTimeout)
                    clearTimeout(me.connTimeout);
            }
            else if (conn.readyState == 4)
            {
                if (me.connTimeout)
                    clearTimeout(me.connTimeout);

                if (me.opTimeout)
                    clearTimeout(me.opTimeout);

                var pError = false;
                me.lastResponse = conn.responseText;

                if (conn.status != 200)
                    pError = true;

                // Standart connection handler
                if (fOnEnd)
                    fOnEnd(conn.responseText, pError, 'HTTP status: ' + conn.status);

                // Advanced connection end handler
                else if (fOnEndAdvanced)
                {
                    pResult = conn.responseText;

                    // connection error
                    if (pError)
                        fOnEndAdvanced(null, JSConsts.ajaxError.connectionError, 'HTTP status: ' + conn.status);
                    // empty result
                    else if (!pResult)
                        fOnEndAdvanced(null, JSConsts.ajaxError.emptyResult, 'Request returned an empty string');
                    // transaction error
                    else if (pResult.indexOf('ERR:') == 0)
                        fOnEndAdvanced(null, JSConsts.ajaxError.transactionError, pResult);
                    else
                    {
                        var evalError = false;

                        try { pResult = eval(pResult); } catch (e) { evalError = true; }

                        // Evaluation error
                        if (evalError)
                        {
                            if (!me.debugMode)
                                fOnEndAdvanced(null, JSConsts.ajaxError.evalError, 'Unable to parse server response');
                            else
                                fOnEndAdvanced(null, JSConsts.ajaxError.evalError, 'Unable to parse server response:\n\n' +
                                               me.lastResponse);
                        }
                        // Operation error
                        else if (pResult.error != 'no')
                            fOnEndAdvanced(null, JSConsts.ajaxError.operationError, pResult.error);
                        else
                            fOnEndAdvanced(pResult, 0, '');
                    }
                }
            }
        }

        try
        {
            conn.send(paramsLine);
        }
        catch(err)
        {
            if (this.onEnd)
                this.onEnd('', true, err.message);
        }
    }

    /*
        Aborts the connection
    */
    this.abort = function()
    {
        if (this.connTimeout)
            clearTimeout(this.connTimeout);

        if (this.conn)
        {
            this.conn.onreadystatechange = null;
            this.conn.abort();
        }
    }

}

// -------------------------------------------------------------------------------------------------
//      The $element() function
// -------------------------------------------------------------------------------------------------

window.$element = function(pId)
{
    var obj = new JSIsisElement();
    obj.element(pId);
    return obj;
}

