//
// psCrossBrowser JavaScript Library
// Copyright (c) 2005 Palos & Sons SRL - The Experts
// Author: Valeriu Palos
// Version: 0.2.0
// Send bugs, improvements and suggestions to: valeriu@palos.ro
//
// Description: This is a library containing several functions which
//              have been tested to work successfully on most of the
//              more popular browsers such as Firefox, MSIE 5+,
//              Opera 8+, Mozilla 1.4+, Netscape 7+). These functions
//              should work without generating errors on older versions
//              of those browsers, even on the infamous Netscape 4.x
//              but with limited functionality.
//
// License: LGPL (Lesser General Public License)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

// Get some browser capabilities
function PS_getBrowserInfo()
{
    function PS_CAPABILITIES()
        {
        this.browserName=false;
        this.browserVersion=false;
        this.engine=false;
        this.engineVersion=false;
        this.cookies=false;
        this.MSIE=false;
        this.NETSCAPE=false;
        this.OPERA=false;
        this.GECKO=false;
        }
    var caps=new PS_CAPABILITIES();
    var temp=0;
    if(navigator)
        {
        //get browser name
        caps.browserName=navigator.appName;

        //get engine description and version
        caps.engine=navigator.userAgent;
        caps.engineVersion=parseFloat(navigator.appVersion);

        //detect if cookies are available
        if(navigator.cookieEnabled)
            caps.cookies=navigator.cookieEnabled;
        else
            {
            document.cookie="testCookieName=1234567; path=/";
            caps.cookies=document.cookie.indexOf("testCookieName")>-1;
            }

        //individual browser variables
        //Opera browser
        caps.OPERA=(navigator.userAgent.indexOf("Opera")>-1);
        if(!caps.OPERA)
            {
            //Microsoft Internet Explorer
            caps.MSIE=(navigator.appName.indexOf("Microsoft")>-1) &&
                                //might be Opera disguised as MSIE
                                (navigator.userAgent.indexOf("Opera")==-1);
            if(navigator.userAgent.indexOf("Gecko")>-1)
                {
                //Netscape 6+
                caps.NETSCAPE=(navigator.userAgent.indexOf("Netscape")!=-1);
                //Gecko, Mozilla, K-meleon etc.
                caps.GECKO=!caps.NETSCAPE;
                }
                else
                //Netscape 4.xx
                caps.NETSCAPE=(navigator.appName.indexOf("Netscape")>-1);
            }

        //browser version
        //browser version for Netscape 4
        caps.browserVersion=caps.engineVersion;
        if(caps.OPERA)
            {
            temp=navigator.userAgent.indexOf("Opera");
            caps.browserVersion=temp>-1?
                parseFloat(navigator.userAgent.substr(temp+6)):0;
            }
        if(caps.MSIE)
            {
            temp=navigator.userAgent.indexOf("MSIE");
            caps.browserVersion=temp>-1?
             parseFloat(navigator.userAgent.substr(temp+5)):0;
            caps.engineVersion=caps.browserVersion;
            }
        if(caps.GECKO)
            {
            temp=navigator.userAgent.indexOf("rv:");
            caps.browserVersion=(temp>-1)?
                parseFloat(navigator.userAgent.substr(temp+3)):0;
            }
        //Netscape 6+
        if(caps.NETSCAPE && (caps.engineVersion>=5))
            {
            temp=navigator.userAgent.indexOf("Netscape/");
            caps.browserVersion=temp>-1?
                parseFloat(navigator.userAgent.substr(temp+9)):0;
            }
        //counteract the Opera disguising mechanism
        if(caps.OPERA && (caps.browserName.indexOf('Opera')==-1))
            {
            caps.browserName='Opera';
            caps.engineVersion=caps.browserVersion;
            }
        }
    return caps;
}

// Get an object by name or id
function PS_getObject(pID)
{
    if(document.all)
        return document.all[pID]==null?
                     false:document.all[pID];
    if(document.getElementById)
        return document.getElementById(pID);
    if(document[pID])
        return document[pID];
    return false;
}

// Set an object's visibility
function PS_setVisibility(pObj,visible)
{
    if(pObj)
        {
        if(pObj.visibility)
            {
            pObj.visibility=visible?'show':'hide';
            return true;
            }
        else if(pObj.style)
            {
            pObj.style.visibility=visible?'visible':'hidden';
            return true;
            }
        }
    return false;
}

// Set an object's transparency
function PS_setAlpha(pObj,alpha)
{
    pObj.style.opacity=alpha;
	pObj.style.filter='alpha(opacity='+Math.round(alpha*100)+')';
}

// Make an object exist or not in the DOM structure
function PS_setExistence(pObj,existent)
{
    //this is necessary because Opera 6- browsers
    //act as if it would work but it doesn't
    var bi=PS_getBrowserInfo();
    if(bi.OPERA && bi.browserVersion<7)
        return false;

    if(pObj)
        {
        if(pObj.style)
            {
            pObj.style.display=existent?'block':'none';
            return true;
            }
        }
    return false;
}

// Get the absolute position of a certain object
function PS_getPosition(pObj)
{
    function PS_point()
        {
        this.x=0;
        this.y=0;
        }
    var p=new PS_point();
    if(pObj)
        {
        if(pObj.offsetParent)
            {
            while (pObj.offsetParent)
                {
                p.x+=pObj.offsetLeft;
                p.y+=pObj.offsetTop;
                pObj=pObj.offsetParent;
                }
            return p;
            }
        else if(pObj.getBoundingClientRect &&
                        document.body &&
                        document.body.clientLeft)
            {
            var pObjRect=pObj.getBoundingClientRect();
            p.x=pObjRect.left-document.body.clientLeft;
            p.y=pObjRect.top-document.body.clientTop;
            return p;
            }
        else if(pObj.x)
            {
            p.x=pObj.x;
            p.y=pObj.y;
            return p;
            }
        }
    p.x=false;
    p.y=false;
    return p;
}

// Set the absolute position of a given object
function PS_setPosition(pObj,x,y)
{
    if(pObj)
        {
        if(pObj.left)
            {
            pObj.left=x;
            pObj.top=y;
            return true;
            }
        else if(pObj.style)
            {
            pObj.style.left=x;
            pObj.style.top=y;
            return true;
            }
        }
    return false;
}

// Set the position of a given object relative to another existing object
function PS_setPositionFromMarker(mObj,pObj,x,y)
{
    mpos=PS_getPosition(mObj);
    if(pObj)
        {
        if(pObj.left)
            {
            pObj.left=mpos.x+x;
            pObj.top=mpos.y+y;
            return true;
            }
        else if(pObj.style)
            {
            pObj.style.left=mpos.x+x;
            pObj.style.top=mpos.y+y;
            return true;
            }
        }
    return false;
}

// Get the size of an object as a {width,height} structure
function PS_getSize(pObj)
{
    function PS_point()
    {
        this.width=-1;
        this.height=-1;
    }
    var p=new PS_point();
    if(pObj)
        {
        if(pObj.offsetWidth)
            {
            p.width=pObj.offsetWidth;
            p.height=pObj.offsetHeight;
            return p;
            }
        else if(pObj.clip)
            {
            p.width=pObj.clip.width;
            p.height=pObj.clip.height;
            return p;
            }
        else if(pObj.style.pixelWidth)
            {
            p.width=pObj.style.pixelWidth;
            p.height=pObj.style.pixelHeight;
            return p;
            }
        }
    p.width=false;
    p.height=false;
    return p;
}

// Set the size fo an object
function PS_setSize(pObj,width,height)
{
    if(width>0 && height>0 && pObj)
        {
        if(pObj.style)
            {
            //sometimes needed for MSIE & Mozilla/NS6
            pObj.style.overflow='hidden';
            pObj.style.width=width;
            pObj.style.height=height;
            if(pObj.style.pixelWidth)
                {
                pObj.style.pixelWidth=width;
                pObj.style.pixelHeight=height;
                }
            return true;
            }
        else if(pObj.clip && pObj.clip.width)
            {
            pObj.clip.width=width;
            pObj.clip.height=height;
            return true;
            }
        }
    return false;
}

// Get the clipping rectangle of an object
function PS_getClipRect(pObj)
{
    function PS_rect()
        {
        this.top=-1;
        this.right=-1;
        this.bottom=-1;
        this.left=-1;
        }
    var r=new rect();
    if(pObj)
        {
        if(pObj.clip)
            {
            r.top=pObj.clip.top;
            r.right=pObj.clip.right;
            r.bottom=pObj.clip.bottom;
            r.left=pObj.clip.left;
            return r;
            }
        else if(pObj.style && pObj.style.clip)
            {
            var clipCS=pObj.style.clip;
            rep=/px/gi;clipCS=clipCS.replace(rep,"");
            rep=/,/gi;clipCS=clipCS.replace(rep,"");
            var clipCV=clipCS.split("rect(")[1].split(")")[0].split(" ");
            r.top=Number(clipCV[0]);
            r.right=Number(clipCV[1]);
            r.bottom=Number(clipCV[2]);
            r.left=Number(clipCV[3]);
            return r;
            }
        }
    r.top=r.right=r.bottom=r.left=false;
    return r;
}

// Set the clipping rectangle of an object
function PS_setClipRect(pObj,top,right,bottom,left)
{
    if(pObj)
        {
        if(pObj.clip)
            {
            pObj.clip.top = top
            pObj.clip.right = right
            pObj.clip.bottom = bottom
            pObj.clip.left = left;
            return true;
            }
        else if(pObj.style)
            {
            pObj.style.clip = "rect("+top+"px "+right+
                "px "+bottom+"px "+left+"px)";
            return true;
            }
        }
        else
    return false;
}

// Load HTML content into an IFRAME ro FRAME object
function PS_loadDocument(pObj,pURL)
{
    //this is necessary because Opera 6- browsers
    //act as if it would work but it doesn't
    var bi=getBrowserInfo();
    if(bi.OPERA && bi.browserVersion<7)
        return false;

    if(pObj)
        {
        if(pObj.src)
            {
            pObj.src=pURL;
            return true;
            }
        else if(pObj.load)
            return pObj.load(pURL);
        }
    return false;
}

// Set the content of a certain object in the DOM
function PS_setContent(pObj,HTMLCode)
{
    if(pObj)
        {
        if(pObj.innerHTML)
            {
            pObj.innerHTML=HTMLCode;
            return true;
            }
        else if(pObj.document && document.layers)
            {
            pObj.document.open();
            pObj.document.write(HTMLCode);
            pObj.document.close();
            return true;
            }
        }
    return false;
}

// Gets the current scroll offset of the page
function PS_getScrollOffset(pWindow)
{

    function PS_point()
        {
        this.scrollLeft=-1;
        this.scrollTop=-1;
        }
    var p=new PS_point();

    //this is necessary because Opera 5- browsers
    //act as if it would work but it doesn't
    var bi=getBrowserInfo();
    if(bi.OPERA && bi.browserVersion<6)
        {
        p.scrollLeft=false;
        p.scrollTop=false;
        return p;
        }

    if(pWindow)
        {
        if(pWindow.document.layers)
            {
            p.scrollLeft=pWindow.pageXOffset;
            p.scrollTop=pWindow.pageYOffset;
            return p;
            }
        else if(pWindow.document.body &&
                        pWindow.document.body.scrollLeft!=null)
            {
            p.scrollLeft=pWindow.document.body.scrollLeft;
            p.scrollTop=pWindow.document.body.scrollTop;
            return p;
            }
        }
    p.scrollLeft=false;
    p.scrollTop=false;
    return p;
}

// Scroll the page to the certain absolute position
function PS_scrollPage(pWindow,scrollLeft,scrollTop)
{
    if(pWindow && pWindow.scrollTo)
        {
        pWindow.scrollTo(scrollLeft,scrollTop);
        return true;
        }
    return false;
}

// Scroll the page relatively by the given amount
function PS_scrollPageBy(pWindow,scrollLeft,scrollTop)
{
    if(pWindow && pWindow.scrollBy)
        {
        pWindow.scrollBy(scrollLeft,scrollTop);
        return true;
        }
    return false;
}

// Get the position of the browser window
function PS_getWindowPosition(pWindow)
{
    function PS_point()
        {
        this.x=-1;
        this.y=-1;
        }
    var p=new PS_point();
    if(pWindow && pWindow.document)
        {
        if(pWindow.screenX)
            {
            p.x=pWindow.screenX;
            p.y=pWindow.screenY;
            return p;
            }
        else if(pWindow.screenLeft)
            {
            p.x=pWindow.screenLeft;
            p.y=pWindow.screenTop;
            return p;
            }
        else if(pWindow.event && pWindow.event.clientX)
            {
            p.x=pWindow.event.screenX-pWindow.event.clientX;
            p.y=pWindow.event.screenY-pWindow.event.clientY;
            return p;
            }
        }
    p.x=false;
    p.y=false;
    return p;
}

// Set the absolute position of the browser window on the desktop
function PS_setWindowPosition(pWindow,x,y)
{
    if(pWindow && pWindow.moveTo)
        {
        pWindow.moveTo(x,y);
        return true;
        }
    return false;
}

// Set the relative position of the browser window on the desktop
function PS_setWindowPositionBy(pWindow,x,y)
{
    if(pWindow && pWindow.moveBy)
        {
        pWindow.moveBy(x,y);
        return true;
        }
    return false;
}

// Get the size of the browser window
function PS_getWindowSize(pWindow)
{
    function PS_point()
        {
        this.width=-1;
        this.height=-1;
        }
    var p=new PS_point();
    if(pWindow && pWindow.document)
        {
        if(pWindow.innerWidth)
            {
            p.width=pWindow.innerWidth;
            p.height=pWindow.innerHeight;
            return p;
            }
        else if(pWindow.document.body &&
                        pWindow.document.body.clientWidth!=null)
            {
            p.width=pWindow.document.body.clientWidth;
            p.height=pWindow.document.body.clientHeight;
            return p;
            }
        }
    p.width=false;
    p.height=false;
    return p;
}

// Set the size of the browser window
function PS_setWindowSize(pWindow,width,height)
{
    if(pWindow && pWindow.resizeTo)
        {
        pWindow.resizeTo(width,height);
        return true;
        }
    return false;
}

// Get the size of the browser window, relatively
function PS_setWindowSizeBy(pWindow,width,height)
{
    if(pWindow && pWindow.resizeBy)
        {
        pWindow.resizeBy(width,height);
        return true;
        }
    return false;
}

// Transition function. Applies an array of transition functions to an object
// with increasing/decreasing (ms) speed (<1 - speed up,
// 1 - constant speed, >1 - slow down). The execute parameter is a string
// of JavaScript code to be executed at the end of the process.
// In this function the obejct name is passed and not the object itself.
function PS_transition(objName,transitions,way,execute,steps)
{
    PS_T_steps=15;
    if(steps)
        PS_T_steps=steps;

    // FADE Transition: Fade object from alpha A to alpha B (values from 0 to 0.9999)
    // tr is like... [A, B].
    // This function is to be passed as a parameter to the PS_transition function
    function PS_T_fade(pObj,tr)
    {
        if(!pObj || !tr.length)
            return;

        if(tr.length<3)
        {
            tr[2]=(tr[1]-tr[0])/PS_T_steps;
            tr[3]=tr[0];
        }

        if((tr[2]==0) ||
           ((tr[2]>0) && (tr[3]>=(tr[1]-0.0001))) ||
           ((tr[2]<0) && (tr[3]<=(tr[1]+0.0001))))
        {
            PS_setAlpha(pObj,tr[1]);
            return tr;
        }

        PS_setAlpha(pObj,tr[3]);
        tr[3]+=tr[2];

        return tr;
    }

    // CLIP Transition: Clip object from one clipping coordinate set to another
    // tr is like... [[top1,right1,bottom1,left1],[top2,right2,bottom2,left2]].
    // This function is to be passed as a parameter to the PS_transition function
    function PS_T_clip(pObj,tr)
    {
        if(!pObj || !tr.length)
            return;

        if(tr.length<3)
        {
            tr[2]=new Array();
            tr[3]=new Array();

            tr[2][0]=(tr[1][0]-tr[0][0])/PS_T_steps;
            tr[2][1]=(tr[1][1]-tr[0][1])/PS_T_steps;
            tr[2][2]=(tr[1][2]-tr[0][2])/PS_T_steps;
            tr[2][3]=(tr[1][3]-tr[0][3])/PS_T_steps;

            tr[3][0]=tr[0][0];
            tr[3][1]=tr[0][1];
            tr[3][2]=tr[0][2];
            tr[3][3]=tr[0][3];
        }

        if((tr[2][0]==0 && tr[2][1]==0 && tr[2][2]==0 && tr[2][3]==0) ||

           ( (tr[2][0]>0) && ( tr[3][0] >= (tr[1][0]-0.0001) ) ) ||
           ( (tr[2][1]>0) && ( tr[3][1] >= (tr[1][1]-0.0001) ) ) ||
           ( (tr[2][2]>0) && ( tr[3][2] >= (tr[1][2]-0.0001) ) ) ||
           ( (tr[2][3]>0) && ( tr[3][3] >= (tr[1][3]-0.0001) ) ) ||

           ( (tr[2][0]<0) && ( tr[3][0] <= (tr[1][0]+0.0001) ) ) ||
           ( (tr[2][1]<0) && ( tr[3][1] <= (tr[1][1]+0.0001) ) ) ||
           ( (tr[2][2]<0) && ( tr[3][2] <= (tr[1][2]+0.0001) ) ) ||
           ( (tr[2][3]<0) && ( tr[3][3] <= (tr[1][3]+0.0001) ) ))
        {
            PS_setClipRect(pObj,tr[1][0],tr[1][1],tr[1][2],tr[1][3]);
            return tr;
        }

        PS_setClipRect(pObj,tr[3][0],tr[3][1],tr[3][2],tr[3][3]);
        tr[3][0]+=tr[2][0];
        tr[3][1]+=tr[2][1];
        tr[3][2]+=tr[2][2];
        tr[3][3]+=tr[2][3];

        return tr;
    }

    // MOVE Transition: Move object coordinate set to another
    // tr is like... [[top1,left1],[top2,left2]].
    // This function is to be passed as a parameter to the PS_transition function
    function PS_T_move(pObj,tr)
    {
        if(!pObj || !tr.length)
            return;

        if(tr.length<3)
        {
            tr[2]=new Array();
            tr[3]=new Array();

            tr[2][0]=(tr[1][0]-tr[0][0])/PS_T_steps;
            tr[2][1]=(tr[1][1]-tr[0][1])/PS_T_steps;

            tr[3][0]=tr[0][0];
            tr[3][1]=tr[0][1];
        }

        if((tr[2][0]==0 && tr[2][1]==0) ||

           ( (tr[2][0]>0) && ( tr[3][0] >= (tr[1][0]-0.0001) ) ) ||
           ( (tr[2][1]>0) && ( tr[3][1] >= (tr[1][1]-0.0001) ) ) ||

           ( (tr[2][0]<0) && ( tr[3][0] <= (tr[1][0]+0.0001) ) ) ||
           ( (tr[2][1]<0) && ( tr[3][1] <= (tr[1][1]+0.0001) ) ))
        {
            PS_setPosition(pObj,tr[1][0],tr[1][1]);
            return tr;
        }

        PS_setPosition(pObj,tr[3][0],tr[3][1]);
        tr[3][0]+=tr[2][0];
        tr[3][1]+=tr[2][1];

        return tr;
    }

    function PS_doTransitions(pObj,tra)
    {
        for(i=0;tra.length>i;i++)
        {
            switch(tra[i][0])
            {
                case 'fade':
                    tra[i][1]=PS_T_fade(pObj,tra[i][1]);
                    break;
                case 'clip':
                    tra[i][1]=PS_T_clip(pObj,tra[i][1]);
                    break;
                case 'move':
                    tra[i][1]=PS_T_move(pObj,tra[i][1]);
                    break;
            }
        }
        return tra;
    }

    pObj=PS_getObject(objName);
    if(!pObj || !transitions.length)
        return;


    if(arguments.length<4)
        execute=';';

    if(!window.PS_T_objects)
        window.PS_T_objects=new Array();
    if(!window.PS_T_timers)
        window.PS_T_timers=new Array();
    if(!window.PS_T_transitions)
        window.PS_T_transitions=new Array();

    if(6>arguments.length)
    {
        PS_cancelTransition(objName);
        pos=-1;
        for(i=0;window.PS_T_objects.length>i;i++)
            if(window.PS_T_objects[i]==objName)
                pos=i;

        if(pos!=-1)
        {
            window.clearTimeout(window.PS_T_timers[pos]);
            transitions=window.PS_T_transitions[pos];
            if(transitions[pos])
                for(i=0;transitions[pos].length>i;i++)
                    transitions[pos][i]=false;
        }

        pos=window.PS_T_objects.length;

        window.PS_T_objects[pos]=objName;
        window.PS_T_transitions[pos]=PS_doTransitions(pObj,transitions);
        window.PS_T_timers[pos]=window.setTimeout('PS_transition(\''+objName+'\',window.PS_T_transitions,\''+way+'\',\''+execute+'\','+PS_T_steps+','+pos+','+0+')',steps);
    }
    else
    {
        if(arguments[6]>=PS_T_steps)
        {
            PS_cancelTransition(objName);
            eval(execute);
            return;
        }
        window.PS_T_transitions[arguments[5]]=PS_doTransitions(pObj,transitions[arguments[5]]);
        window.PS_T_timers[arguments[5]]=window.setTimeout('PS_transition(\''+objName+'\',window.PS_T_transitions,\''+way+'\',\''+execute+'\','+arguments[4]+','+arguments[5]+','+(arguments[6]*1+1)+')',steps);
    }
}

// Cancel the transition for an object.
function PS_cancelTransition(objName)
{
    pObj=PS_getObject(objName);
    if(!pObj)
        return;

    if(!window.PS_T_objects)
        return;
    if(!window.PS_T_timers)
        return;
    if(!window.PS_T_transitions)
        return;

    for(i=0;window.PS_T_objects.length>i;i++)
        if(window.PS_T_objects[i]==objName)
        {
            window.clearTimeout(window.PS_T_timers[i]);
            window.PS_T_transitions[i]=false;
            window.PS_T_objects[i]=false;
            window.PS_T_timers[i]=false;
            break;
        }
}
