function htmlEncode(pString)
{
	var str = String(pString).valueOf();
	
	str = str.replace(/\</gi, "&lt;");
	str = str.replace(/\>/gi, "&gt;");
	str = str.replace(/\&/gi, "&amp;");
	str = str.replace(/\"/gi, "&quot;");
	str = str.replace(/\n/gi, "<BR>");
	
	return str;
}

function htmlDecode(pString)
{
	var str = String(pString).valueOf();
	
	str = str.replace(/\<BR\>/gi, "\n");
	str = str.replace(/\&lt;/gi, "<");
	str = str.replace(/\&gt;/gi, ">");
	str = str.replace(/\&amp;/gi, "&");
	str = str.replace(/\&quot;/gi, "\"");
	
	return str;
}

function safe_str(pString)
{
	if (pString != null)
	{
		return String(pString).valueOf();
	}
	
	return "";
}

function getAbsoluteLeft(pObject)
{
	var result = 0;
	
	var obj = pObject;
	while (obj != null)
	{
		result += obj.offsetLeft;
		
		obj = obj.offsetParent;
	}
	
	return result;
}

function getAbsoluteTop(pObject)
{
	var result = 0;
	
	var obj = pObject;
	while (obj != null)
	{
		result += obj.offsetTop;

		obj = obj.offsetParent;
	}
	
	return result;
}

function getObjectSize(pObject)
{
	var size = {
		width: pObject.offsetWidth,
		height: pObject.offsetHeight
	};
	
	return size;
}

function getObjectPosition(pObject)
{
	var pos = {
		left: getAbsoluteLeft(pObject),
		top: getAbsoluteTop(pObject)
	};
	
	return pos;
}

function getObjectBounds(pObject)
{
	var size = getObjectSize(pObject);
	var pos = getObjectPosition(pObject);
	
	var bounds = {
		left:	pos.left,
		top:	pos.top,
		width:	size.width,
		height:	size.height
	};
	
	return bounds;
}

function CompareElementRecursive(pObject, pCompareTo)
{
    var obj = pObject;
    
    while (obj)
    {
        if (obj.id == pCompareTo.id)
            return true;
        
        obj = obj.parentNode;
    }
    
    return false;
}

function fadeElement(id, end, step, delay, callback)
{
    var timer = setInterval(
        function()
        {
            try
            {
                var curr = $(id).getOpacity();
                
                if (curr < end)
                {
                    curr += step;
                    if (curr > end) curr = end;
                }
                else if (curr > end)
                {
                    curr -= step;
                    if (curr < end) curr = end;
                }
                
                $(id).setOpacity(curr);
                
                if (curr >= end)
                {
                    clearInterval(timer);

                    if (callback)
                    {
                        //setTimeout(
                        //    function()
                        //    {
                                callback();
                        //    },
                        //    100
                        //);
                    }
                }
            }
            catch(e)
            {
                alert("fadeElement: " + e);
            }
        },
        10
    );
}

function zoomElement(id, amount)
{
    var obj = $(id).cloneNode(true);

    obj.className = $(id).className;
    obj.style.position = "absolute";
    obj.style.zIndex = 60000;
    
    var bounds = getObjectBounds($(id));
    
    obj.style.left = bounds.left;
    obj.style.top = bounds.top;
    obj.style.width = bounds.width;
    obj.style.height = bounds.height;
    
    var aspect = bounds.height / bounds.width;
    
    document.body.appendChild(obj);
//    alert($(id).parentNode.outerHTML);

    var step = amount / 10;
    
    var curr = 0;
    
    $(obj).setOpacity(0.1);
   
    obj._zoomElementTimer = setInterval(
        function()
        {
            curr += step;
            
            var target = getObjectBounds($(obj));

            target.left -= curr;
            target.top -= (curr * aspect);
            target.width += (curr * 2);
            target.height += (curr * aspect * 2);
            
            obj.style.left = target.left;
            obj.style.top = target.top;
            obj.style.width = target.width;
            obj.style.height = target.height;
            
            if (curr > 0)
                $(obj).setOpacity(curr / amount);
            
            if (curr >= amount)
            {
                clearInterval(obj._zoomElementTimer);
                
                obj._zoomElementTimer = null;
            }
        },
        10
    );
}

function smoothMoveX(pElement, pEnd)
{
    if ($(pElement)._scrollBusy)
    {
        return;
    }
        
    $(pElement)._scrollBusy = true;

    var initPos = parseInt($(pElement).style.left);
    if (isNaN(initPos)) initPos = 0;
    var delta = Math.abs(initPos - parseInt(pEnd));
    var t = 10;
    var v0 = Math.round(delta / t * 1.5);
    var a = (delta - (v0 * t)) / (t * t);
  
    var currT = 0;
    
    var timer = setInterval(
        function()
        {
            ++currT;
            
            var pos = initPos;
            
            if (pEnd > initPos)
                pos = pos + Math.abs((v0 * currT) + (a * currT * currT));
            else
                pos = pos - Math.abs((v0 * currT) + (a * currT * currT));
            
            $(pElement).style.left = pos;
            
            if (currT >= t)
            {
                clearInterval(timer);
                
                $(pElement).style.left = pEnd;
                
                $(pElement)._scrollBusy = false;
            }
        },
        10
    );
}

function smoothMoveY(pElement, pEnd)
{
    if ($(pElement)._scrollBusy)
        return;
        
    $(pElement)._scrollBusy = true;

    var initPos = parseInt($(pElement).style.top);
    if (isNaN(initPos)) initPos = 0;
    var delta = Math.abs(initPos - parseInt(pEnd));
    var t = 7;
    var v0 = Math.round(delta / t * 1.5);
    var a = (delta - (v0 * t)) / (t * t);
  
    var currT = 0;
    
    var timer = setInterval(
        function()
        {
            ++currT;
            
            var pos = initPos;
            
            if (pEnd > initPos)
                pos = pos + Math.abs((v0 * currT) + (a * currT * currT));
            else
                pos = pos - Math.abs((v0 * currT) + (a * currT * currT));
            
            $(pElement).style.top = pos;
            
            if (currT >= t)
            {
                clearInterval(timer);
                
                $(pElement).style.top = pEnd;
                
                $(pElement)._scrollBusy = false;
            }
        },
        10
    );
}

function setupHScroll(pContainerID, pLeftID, pRightID, pDelta)
{
    $(pContainerID).style.position = "relative";
    $(pContainerID).style.left = 0;

    Event.observe(pLeftID, "mouseover",
        function()
        {
            var containerWidth = Element.getWidth($(pContainerID).parentNode);
            var contentWidth = Element.getWidth($(pContainerID));

            if (contentWidth > containerWidth)
            {
                var pos = parseInt($(pContainerID).style.left);
                if (isNaN(pos)) pos = 0;

                pos -= pDelta;

                if (pos < -(contentWidth - containerWidth))
                    pos = -(contentWidth - containerWidth);

                smoothMoveX(pContainerID, pos);
            }
        }
    );

    Event.observe(pRightID, "mouseover",
        function()
        {
            var containerWidth = Element.getWidth($(pContainerID).parentNode);
            var contentWidth = Element.getWidth($(pContainerID));

            if (contentWidth > containerWidth)
            {
                var pos = parseInt($(pContainerID).style.left);
                if (isNaN(pos)) pos = 0;
                
                pos += pDelta;
                if (pos > 0) pos = 0;
                
                smoothMoveX(pContainerID, pos);
            }
        }
    );
}

function setupVScroll(pContainerID, pDownID, pUpID, pDelta)
{
    $(pContainerID).style.position = "relative";

    Event.observe(pDownID, "click",
        function()
        {
            var containerHeight = Element.getHeight($(pContainerID).parentNode);
            var contentHeight = Element.getHeight($(pContainerID));

            if (contentHeight > containerHeight)
            {
                var pos = parseInt($(pContainerID).style.top);
                if (isNaN(pos)) pos = 0;
                   
                pos += pDelta;
                if (pos > 0) pos = 0;

                smoothMoveY(pContainerID, pos);
            }
        }
    );

    Event.observe(pUpID, "click",
        function()
        {
            var containerHeight = Element.getHeight($(pContainerID).parentNode);
            var contentHeight = Element.getHeight($(pContainerID));

            if (contentHeight > containerHeight)
            {
                var pos = parseInt($(pContainerID).style.top);
                if (isNaN(pos)) pos = 0;

                pos -= pDelta;

                if (pos < -(contentHeight - containerHeight))
                    pos = -(contentHeight - containerHeight);

//                if (pos + contentHeight < containerHeight)
//                    pos = containerHeight - contentHeight;

                smoothMoveY(pContainerID, pos);
            }
        }
    );
}
var g___OpacityQueue                = new Queue();
var g___OpacityRequestInProgress    = false;
var g___OpacityQueueEmptyCallbacks  = new Array();

function opacityFade(pID, pTo, pDelay, pCallback)
{
    if (!pID) return;
    
    var rec = { id: pID, to: pTo, delay: pDelay, callback: pCallback };
   
    g___OpacityQueue.enqueue(rec);
    
    _opacityFadeNext();
}

function opacityAddQueueEmptyCallback(pCallback)
{
    g___OpacityQueueEmptyCallbacks[g___OpacityQueueEmptyCallbacks.length] = pCallback;
}

function _opacityFadeNext()
{
    if (g___OpacityRequestInProgress) return;

    var rec = g___OpacityQueue.dequeue();
    
    if (rec == null)
    {
        for (var i = 0; i < g___OpacityQueueEmptyCallbacks.length; ++i)
        {
            var callback = g___OpacityQueueEmptyCallbacks[i];
            
            if (callback)
                callback();
        }
        
        g___OpacityQueueEmptyCallbacks = new Array();
        
        return;
    }
    
    g___OpacityRequestInProgress = true;
         
    fadeElement(rec.id, rec.to, 0.05, rec.delay,
        function()
        {
            if (rec.callback)
                rec.callback();
                
            setTimeout(
                function()
                {
                    g___OpacityRequestInProgress = false;
                    
                    _opacityFadeNext();
                },
                1
            );
        }
    );
}

function Queue()
{
    this._head = null;
    this._tail = null;
    
    this.enqueue = function(pData)
    {
        var rec = { next: null, data: pData };
        
        if (this._tail != null)
            this._tail.next = rec;
        
        this._tail = rec;
        
        if (this._head == null)
            this._head = rec;
    }
    
    this.dequeue = function()
    {
        var rec = this._head;
        
        if (rec != null)
        {
            this._head = this._head.next;
            
            if (this._head == null)
                this._tail = null;
        }
        
        if (rec != null)
            return rec.data;
        else
            return null;
    }
    
    this.empty = function()
    {
        if (this._head == null)
            return true;
        else
            return false;
    }
}
