function BitList( )
{
    this.set = set;
}

function set( value, id, idAny, idYes, idNo, callback )
{
    var oAny = document.getElementById( idAny );
    var oYes = document.getElementById( idYes );
    var oNo  = document.getElementById( idNo );
    var oHidden = document.getElementById( id );

    switch ( value )
    {
        case 0:
            oAny.className  = 'bitlist-div-any bitlist-div-selected';
            oYes.className  = 'bitlist-div-yes';
            oNo.className   = 'bitlist-div-no';
            break;
        case 1:
            oAny.className  = 'bitlist-div-any';
            oYes.className  = 'bitlist-div-yes bitlist-div-selected';
            oNo.className   = 'bitlist-div-no';
            break;
        case 2:
            oAny.className  = 'bitlist-div-any';
            oYes.className  = 'bitlist-div-yes';
            oNo.className   = 'bitlist-div-no bitlist-div-selected';
            break;
        default:
            alert( 'BitLister: invalid value (' + value + ')' );
            break;
    }

    oHidden.value = value;
    if ( callback ) eval( callback );
}

oBitLister = new BitList;

// -------------------------------------------------------------------------
// Sliderbar control
// -------------------------------------------------------------------------

function SliderControl( )
{
    this.startDiv = '';
    this.middleDiv = '';
    this.endDiv = '';
    this.startBall = '';
    this.endBall = '';
    this.selectionList = '';
    this.lGuideLabel = '';
    this.rGuideLabel = '';

    this.width = 0;
    this.valueStep = 0
    this.guideWidth = 0;
    this.itemsCount = 0;

    this.lDragStarted = 0;
    this.rDragStarted = 0;

    this.lInitPosx = 0;
    this.rInitPosx = 0;

    this.lStartOffsetX = 0;
    this.rStartOffsetX = 0;

    this.zIndex = 100;
    this.eventCallback = '';

}

function SliderManager( )
{
    this.sliders = [];
    this.registerSlider = registerSlider;

}

function registerSlider( elementId, pixelWidth, guideWidth,
                         selIndexStart, selIndexEnd, callback )
{
    // Search in the whole document to find container elements
    // with class name 'sliderbar'
    var node = document.getElementById( elementId );
    if ( !node )
    {
        alert( 'Slider element [' + elementId + '] not found' );
        return;
    }

    // Found a slider, create the control object
    var ctrlSlider = new SliderControl( );
    ctrlSlider.eventCallback = callback;

    // Assign important properties
    ctrlSlider.width = pixelWidth;
    ctrlSlider.guideWidth = guideWidth;

    // Assign to the slider the various section objects
    var sliderDivs = node.getElementsByTagName( 'div' );
    ctrlSlider.startDiv  = sliderDivs[ 0 ];
    ctrlSlider.middleDiv = sliderDivs[ 1 ];
    ctrlSlider.endDiv    = sliderDivs[ 2 ];

    // Assign the start/end guides
    ctrlSlider.startBall = document.getElementById( elementId + '-imgstart' );
    ctrlSlider.endBall   = document.getElementById( elementId + '-imgend' );

    // Assign the value labels for left and right guides
    ctrlSlider.lGuideLabel = document.getElementById( elementId + '-llabel' );
    ctrlSlider.rGuideLabel = document.getElementById( elementId + '-rlabel' );

    // Assign the hidden selection list
    ctrlSlider.selectionList = node.getElementsByTagName( 'select' )[ 0 ];
    ctrlSlider.itemsCount = ctrlSlider.selectionList.length;

    if ( ctrlSlider.itemsCount >= 1 )
    {
        // Initialize guides z-index to be used in drag operations
        // in order to be able to always select the currently moving guide
        ctrlSlider.startBall.style.zIndex = ctrlSlider.zIndex;
        ctrlSlider.endBall.style.zIndex = ctrlSlider.zIndex;

        // Compute the slider's value step. Beware, in the list there is
        // always one more item for the 'Any'
        if ( ctrlSlider.itemsCount == 2 )
            ctrlSlider.valueStep = 0;
        else if ( ctrlSlider.itemsCount == 3 )
            ctrlSlider.valueStep = ctrlSlider.width;
        else
            ctrlSlider.valueStep = parseInt(
                    ctrlSlider.width / ( ctrlSlider.itemsCount - 2 ) );

        // Initially we select the 'Any' value which corresponds to the
        // slider's full range
        if ( selIndexStart == '' )
            selIndexStart = 0;
        else
            selIndexStart = parseInt( selIndexStart );

        if ( selIndexEnd == '' )
            selIndexEnd = 0;
        else
            selIndexEnd = parseInt( selIndexEnd );

        if ( selIndexStart < 0 && selIndexEnd < 0 )
        {
            // Set selection
            ctrlSlider.selectionList.selectedIndex = -1;
            ctrlSlider.selectionList.options[ 0 ].selected = true;

            // Adjust guides position
            ctrlSlider.startBall.style.left = 0 + 'px';// - ctrlSlider.guideWidth + 'px';
            ctrlSlider.endBall.style.left = ctrlSlider.width - ctrlSlider.guideWidth + 'px';
            ctrlSlider.lGuideLabel.style.left = 0 + 'px';// - ctrlSlider.guideWidth + 'px';
            ctrlSlider.rGuideLabel.style.left = ctrlSlider.width - ctrlSlider.guideWidth + 'px';

            // Set guides labels
            ctrlSlider.lGuideLabel.innerHTML =
                ctrlSlider.selectionList.options[ 1 ].text;
            ctrlSlider.rGuideLabel.innerHTML =
                ctrlSlider.selectionList.options[ ctrlSlider.itemsCount - 1 ].text;
        }
        else
        {
            // Set selection
            ctrlSlider.selectionList.selectedIndex = -1;

            var start = selIndexStart + 1;
            var end = selIndexEnd + 1;
            for ( var i = start; i <= end; i++ )
                ctrlSlider.selectionList.options[ i ].selected = true;


            ctrlSlider.lGuideLabel.innerHTML =
                ctrlSlider.selectionList.options[ start ].text;
            ctrlSlider.rGuideLabel.innerHTML =
                ctrlSlider.selectionList.options[ end ].text;

            var lx = 0;
            var rx = ctrlSlider.width - ctrlSlider.guideWidth;

            if ( ctrlSlider.valueStep != 0 )
            {
                lx = selIndexStart*ctrlSlider.valueStep;
                rx = selIndexEnd*ctrlSlider.valueStep;

                if ( lx < 0 )
                    lx = 0;

                if ( lx > ( ctrlSlider.width - ctrlSlider.guideWidth ) )
                    lx = ctrlSlider.width - ctrlSlider.guideWidth;


                if ( rx < 0 )
                    rx = 0;

                if ( rx > ( ctrlSlider.width - ctrlSlider.guideWidth ) )
                    rx = ctrlSlider.width - ctrlSlider.guideWidth;

                if ( rx < lx ) rx = lx;
            }


            // Adjust guides position
            ctrlSlider.startBall.style.left = lx + 'px';// - ctrlSlider.guideWidth + 'px';
            ctrlSlider.endBall.style.left = rx + 'px';

            // Set guides value labels
            ctrlSlider.lGuideLabel.style.left = lx + 'px';
            ctrlSlider.rGuideLabel.style.left = rx + 'px';

            lDragEnd( ctrlSlider, null, false );
            rDragEnd( ctrlSlider, null, false );

            if ( lx == rx )
            {
                ctrlSlider.zIndex += 1;
                if ( lx == 0 )
                    ctrlSlider.endBall.style.zIndex = ctrlSlider.zIndex;
                else
                    ctrlSlider.startBall.style.zIndex = ctrlSlider.zIndex;
            }

        }
    }

    // Left slider events registration
    ctrlSlider.startBall.onmousedown = function( event ) { lDragStart( ctrlSlider, event ) };
    ctrlSlider.startBall.onmousemove = function( event ) { lDrag( ctrlSlider, event ) };
    ctrlSlider.startBall.onmouseup = function( event ) { 
        lDragEnd( ctrlSlider, event, true );
    };

    // Right slider events registration
    ctrlSlider.endBall.onmousedown = function( event ) { rDragStart( ctrlSlider, event ) };
    ctrlSlider.endBall.onmousemove = function( event ) { rDrag( ctrlSlider, event ) };
    ctrlSlider.endBall.onmouseup = function( event ) { 
        rDragEnd( ctrlSlider, event, true );
    };

    // Slider bar events registration
    ctrlSlider.startDiv.onclick = function( event ) { barClick( ctrlSlider, event ) };
    ctrlSlider.middleDiv.onclick = function( event ) { barClick( ctrlSlider, event ) };
    ctrlSlider.endDiv.onclick = function( event ) { barClick( ctrlSlider, event ) };

    // Document events registration
    document.onmousedown = function( event ) { docDragStart( ctrlSlider, event ) };
    document.onmousemove = function( event ) { docDrag( ctrlSlider, event ) };
    document.onmouseup = function( event ) { 
        docDragEnd( ctrlSlider, event, true );
    };

    // Store the slider
    this.sliders.push( ctrlSlider );
}

function selectValues( slider )
{
    // Select the values of the select list depending
    // on the positions of the slider guides
    if ( slider.valueStep != 0 )
    {
        var lxpos = parseInt( slider.startBall.style.left );
        var lNumSteps = Math.floor( lxpos / slider.valueStep );

        var rxpos = parseInt( slider.endBall.style.left );
        var rNumSteps = Math.floor( rxpos / slider.valueStep );

        if ( lxpos == 0 && rxpos == ( slider.width - slider.guideWidth ) )
        {
            slider.selectionList.selectedIndex = -1;
            slider.selectionList.options[ 0 ].selected = true;

            slider.lGuideLabel.innerHTML =
                slider.selectionList.options[ 1 ].text;
            slider.rGuideLabel.innerHTML =
                slider.selectionList.options[ slider.itemsCount - 1 ].text;
        }
        else
        {
           var startIndex = 0;
           var endIndex = 0;

           if ( lxpos <= 0 )
               startIndex = 1;
           else if ( lxpos >= ( slider.width - slider.guideWidth ) )
               startIndex = slider.itemsCount - 1;
           else
           {
               startIndex = lNumSteps + 1;
           }

           if ( rxpos <= 0 )
               endIndex = 1;
           else if ( rxpos >= ( slider.width - slider.guideWidth ) )
               endIndex = slider.itemsCount - 1;
           else
           {
               endIndex = rNumSteps + 1;
           }

           slider.selectionList.selectedIndex = -1;
           for ( var i = startIndex; i <= endIndex; i++ )
                slider.selectionList.options[ i ].selected = true;

            // Set label values
            slider.lGuideLabel.innerHTML =
                slider.selectionList.options[ startIndex ].text;
            slider.rGuideLabel.innerHTML =
                slider.selectionList.options[ endIndex ].text;
        }

    }
}

function adjustLabelValue( slider, label )
{
    // Select the values of the select list depending
    // on the positions of the slider guides
    if ( slider.valueStep != 0 )
    {
        var newpos = 0;
        var index = 0;

        var xpos = parseInt( label.style.left );
        var numSteps = Math.floor( xpos / slider.valueStep );
        var dstep = xpos - numSteps*(slider.valueStep);

        if ( dstep < ( slider.valueStep / 2 ) )
           index = numSteps + 1;
        else
           index = numSteps + 2;

       label.innerHTML = slider.selectionList.options[ index ].text;
    }
}

function barClick( slider, e )
{
     if ( !e ) e = window.event;

    // Get the positions of the two sliders
    var lInitPosx = parseInt( slider.startBall.style.left );
    var rInitPosx = parseInt( slider.endBall.style.left );

    var lAbsPosx = lInitPosx + e.screenX - e.clientX;
    var rAbsPosx = rInitPosx + e.screenX - e.clientX;

    var p  = getScreenCordinates( slider.startDiv );
    var p1 = getScreenCordinates( slider.startBall );
    var p2 = getScreenCordinates( slider.endBall );

    var loffset = Math.abs( e.screenX - p1.x );
    var roffset = Math.abs( e.screenX - p2.x );

    if ( loffset < roffset )
    {
        // Move left slider
        lGuideMoveTo( slider, ( e.screenX - p.x ), e );
    }
    else
    {
        // Move right slider
        rGuideMoveTo( slider, ( e.screenX - p.x ), e );
    }
}

function lGuideMoveTo( slider, x, e )
{
     // Compute and check for valid values for x position
    if ( x < ( 0 - slider.guideWidth ) )
        x = 0 - slider.guideWidth;

    if ( x > ( slider.width - slider.guideWidth ) )
        x = slider.width - slider.guideWidth;

    var rSliderPosx = parseInt( slider.endBall.style.left );
    if ( x > rSliderPosx ) x = rSliderPosx;

    // Set slider position and label position
     slider.startBall.style.left = x + 'px';
     slider.lGuideLabel.style.left = x + 'px';
     adjustLabelValue( slider, slider.lGuideLabel );

     // Set middle div width to show the 'inner' effect
     slider.middleDiv.style.left = x + 'px';
     slider.middleDiv.style.width = parseInt( slider.endBall.style.left ) -
                                    x + 'px';

     lDragEnd( slider, e );
}

function rGuideMoveTo( slider, xpos, e )
{
     // Compute and check for valid values for x position
    if ( xpos < ( 0 - slider.guideWidth ) )
        xpos = 0 - slider.guideWidth;

    if ( xpos > ( slider.width - slider.guideWidth ) )
        xpos = slider.width - slider.guideWidth;

    var lSliderPosx = parseInt( slider.startBall.style.left );
    if ( xpos < lSliderPosx ) xpos = lSliderPosx;

    slider.endBall.style.left = xpos + 'px';
    slider.rGuideLabel.style.left = xpos + 'px';
    adjustLabelValue( slider, slider.rGuideLabel );

    // Set middle div width to show the 'inner' effect
     slider.middleDiv.style.right = xpos + 'px';
     slider.middleDiv.style.width =
         xpos - parseInt( slider.startBall.style.left ) + 'px';

     rDragEnd( slider, e );
}

function lDragStart( slider, e )
{
    // If the right slider moves, do not start moving
    if ( slider.rDragStarted == 1 ) return;

    // No need to drag if we do not have sufficient items count
    //if ( slider.itemsCount == 2 || slider.itemsCount == 3 ) return;

    if ( !e ) e = window.event;
    slider.startBall.style.backgroundColor = '#0077c1';

    // Compute initial positions and offsets for the guide, so
    // it can be used later during moving
    slider.lStartOffsetX = e.clientX - parseInt( slider.startBall.style.left );
    slider.lInitPosx = e.screenX - e.clientX;

    // Adjust the guide's z-index so it is over the other guide
    slider.zIndex += 1;
    slider.startBall.style.zIndex = slider.zIndex;
    slider.lGuideLabel.style.zIndex = slider.zIndex;

    // Mark that a drag operation is in progress
    slider.lDragStarted = 1;

    //e.cancelBubble = true;
    e.returnValue = false;
}

function lDrag( slider, e )
{
    // Do not drag if a mouse down event did not happen
    if ( slider.lDragStarted == 0 ) return;
    if ( !e ) e = window.event;

    // Compute and check for valid values for x position
    var xpos = e.screenX - slider.lStartOffsetX - slider.lInitPosx;

    if ( xpos < ( 0 - slider.guideWidth ) )
        xpos = 0 - slider.guideWidth;

    if ( xpos > ( slider.width - slider.guideWidth ) )
        xpos = slider.width - slider.guideWidth;

    var rSliderPosx = parseInt( slider.endBall.style.left );
    if ( xpos > rSliderPosx ) xpos = rSliderPosx;

    // Set slider position and label position
     slider.startBall.style.left = xpos + 'px';
     slider.lGuideLabel.style.left = xpos + 'px';
     adjustLabelValue( slider, slider.lGuideLabel );

     // Set middle div width to show the 'inner' effect
     slider.middleDiv.style.left = xpos + 'px';
     slider.middleDiv.style.width = parseInt( slider.endBall.style.left ) -
                                    xpos + 'px';
     //e.cancelBubble = true;
     e.returnValue = false;
}

function lDragEnd( slider, e )
{
    //if ( slider.lDragStarted == 0 ) return;
    if ( !e ) e = window.event;

    // Position the slider to the nearest descrete value
    if ( slider.valueStep != 0 )
    {
        var newpos = 0;
        var xpos = parseInt( slider.startBall.style.left );
        var numSteps = Math.floor( xpos / slider.valueStep );
        var dstep = xpos - numSteps*(slider.valueStep);
        if ( dstep < ( slider.valueStep / 2 ) )
            newpos = numSteps*(slider.valueStep);
        else
            newpos = ( numSteps + 1 )*(slider.valueStep);

        if ( newpos < ( 0 - slider.guideWidth ) )
            newpos = 0 - slider.guideWidth;

        if ( newpos > ( slider.width - slider.guideWidth ) )
            newpos = slider.width - slider.guideWidth;

        var rSliderPosx = parseInt( slider.endBall.style.left );
        if ( newpos > rSliderPosx ) newpos = rSliderPosx;

        slider.startBall.style.left = newpos + 'px';
        slider.lGuideLabel.style.left = newpos + 'px';

        // Set middle div width to show the 'inner' effect
        slider.middleDiv.style.left = newpos + 'px';
        slider.middleDiv.style.width = parseInt( slider.endBall.style.left ) -
                                       newpos + 'px';
        slider.startDiv.style.width = newpos + 'px';
    }

    // Select the values of the select list
    selectValues( slider );

    slider.startBall.style.backgroundColor = '#ddecf7';
    slider.lDragStarted = 0;//alert( slider.startBall.style.left );
    //e.cancelBubble = true;
    if ( e ) e.returnValue = false;
    if ( slider.eventCallback ) eval( slider.eventCallback );
}

function rDragStart( slider, e )
{
    if ( slider.lDragStarted == 1 ) return;

    // No need to drag if we do not have sufficient items count
    //if ( slider.itemsCount == 2 || slider.itemsCount == 3 ) return;

    if ( !e ) e = window.event;
    slider.endBall.style.backgroundColor = '#0077c1';

    slider.rStartOffsetX = e.clientX - parseInt( slider.endBall.style.left );
    slider.rInitPosx = e.screenX - e.clientX;

    // Adjust the guide's z-index so it is over the other guide
    slider.zIndex += 1;
    slider.endBall.style.zIndex = slider.zIndex;
    slider.rGuideLabel.style.zIndex = slider.zIndex;

    slider.rDragStarted = 1;
    //e.cancelBubble = true;
    e.returnValue = false;
}

function rDrag( slider, e )
{
    if ( slider.rDragStarted == 0 ) return;
    if ( !e ) e = window.event;

    var xpos = e.screenX - slider.rStartOffsetX - slider.rInitPosx;
    if ( xpos < ( 0 - slider.guideWidth ) )
        xpos = 0 - slider.guideWidth;

    if ( xpos > ( slider.width - slider.guideWidth ) )
        xpos = slider.width - slider.guideWidth;

    var lSliderPosx = parseInt( slider.startBall.style.left );
    if ( xpos < lSliderPosx ) xpos = lSliderPosx;

    slider.endBall.style.left = xpos + 'px';
    slider.rGuideLabel.style.left = xpos + 'px';
    adjustLabelValue( slider, slider.rGuideLabel );

    // Set middle div width to show the 'inner' effect
     slider.middleDiv.style.right = xpos + 'px';
     slider.middleDiv.style.width =
         xpos - parseInt( slider.startBall.style.left ) + 'px';

     slider.endDiv.style.left = xpos + 'px';
     slider.endDiv.style.width = slider.width - xpos + 'px';
    //e.cancelBubble = true;
    e.returnValue = false;

}

function rDragEnd( slider, e )
{
    //if ( slider.rDragStarted == 0 ) return;
    if ( !e ) e = window.event;

    // Position the slider to the nearest descrete value
    if ( slider.valueStep != 0 )
    {
        var newpos = 0;
        var xpos = parseInt( slider.endBall.style.left );
        var numSteps = Math.floor( xpos / slider.valueStep );
        var dstep = xpos - numSteps*(slider.valueStep);
        if ( dstep < ( slider.valueStep / 2 ) )
            newpos = numSteps*(slider.valueStep);
        else
            newpos = ( numSteps + 1 )*(slider.valueStep);

        if ( newpos < ( 0 - slider.guideWidth ) )
            newpos = 0 - slider.guideWidth;

        if ( newpos > ( slider.width - slider.guideWidth ) )
            newpos = slider.width - slider.guideWidth;

        var lSliderPosx = parseInt( slider.startBall.style.left );
        if ( newpos < lSliderPosx ) newpos = lSliderPosx;

        slider.endBall.style.left = newpos + 'px';
        slider.rGuideLabel.style.left = newpos + 'px';

        // Set middle div width to show the 'inner' effect
        slider.middleDiv.style.right = newpos + 'px';
        slider.middleDiv.style.width =
            newpos - parseInt( slider.startBall.style.left ) + 'px';

        slider.endDiv.style.left = newpos + 'px';
        slider.endDiv.style.width = slider.width - newpos + 'px';
    }

    // Select the values of the select list
    selectValues( slider );

    slider.endBall.style.backgroundColor = '#ddecf7';
    slider.rDragStarted = 0;
    //e.cancelBubble = true;
    if ( e ) e.returnValue = false;
    if ( slider.eventCallback ) eval( slider.eventCallback );
    
}

function docDragStart( slider, e )
{
    if ( !e ) e = window.event;

    //slider.endBall.style.backgroundColor = '#0077c1';
}

function docDrag( slider, e )
{
    if ( !e ) e = window.event;

    for ( var i in oSliderManager.sliders )
    {
        if ( oSliderManager.sliders[ i ].lDragStarted != 0 )
            lDrag( oSliderManager.sliders[ i ], e );

        if ( oSliderManager.sliders[ i ].rDragStarted != 0 )
            rDrag( oSliderManager.sliders[ i ], e )
    }

}

function docDragEnd( slider, e )
{
    if ( !e ) e = window.event;

    for ( var i in oSliderManager.sliders )
    {
        if ( oSliderManager.sliders[ i ].lDragStarted != 0 )
            lDragEnd( oSliderManager.sliders[ i ], e );

        if ( oSliderManager.sliders[ i ].rDragStarted != 0 )
            rDragEnd( oSliderManager.sliders[ i ], e )
    }

}

function getScreenCordinates(obj) {
        var p = {};
        p.x = obj.offsetLeft;
        p.y = obj.offsetTop;
        while (obj.offsetParent) {
            p.x = p.x + obj.offsetParent.offsetLeft;
            p.y = p.y + obj.offsetParent.offsetTop;
            if (obj == document.getElementsByTagName("body")[0]) {
                break;
            }
            else {
                obj = obj.offsetParent;
            }
        }
        return p;
    }


var oSliderManager = new SliderManager;

