
// ---------------------------------------------------------------------
// Beware testing this on Netscape 4.x.
// 1. get the latest 4.x  sub-version (currently 4.79)
// 2. if pages seems to render unreliably, load a different page then
//    reload the page under test.
// 3. why Netscape 4.x requires double-nested SPANs we don't know.
//
// functions:
//	slider_render_all()
//	slider_render()
//	slider_render_scale()
//	slider_render_pane()
//	slider_render_ticks()
//	slider_render_labels()
//	slider_render_stylus_up()
//	slider_render_stylus_down()
//
//	slider_normalise()
//	slider_align()
//
//	slider_stylus_mousedown()
//	slider_stylus_mousemove()
//	slider_stylus_mouseup()
//
//	slider_set_value()
//
// data:
//
// 	a copy of sliders.js must be loaded before this library.
//
//	sliding = a global variable indicating state.
//
// ---------------------------------------------------------------------

var sliding = false;			// state for user drag'n'drop

// ---------------------------------------------------------------------
// create all the sliders in one go
function slider_render_all()
{
    var i;
    for (i=0; i<sliders.length; i++)
    {
	slider_render(sliders[i]);
    }
}

// ---------------------------------------------------------------------
// create the slider specified by some slider[x] object.
function slider_render(obj)
{
var i;
var span;

    with (window.document)
    {
	if (old)
	{
	    write_slider_html(obj,"<BR>No browser support for sliders<BR>");
	    return;
	}
	
	//set up values if not set
	if(!obj.values || obj.values == null){
		//calculate values using number of ticks defined
		obj.values = new Array();
		
		//calculate the step
		var step = (obj.max_value - obj.min_value)/(obj.ticks - 1);
		for(i=0; i<obj.ticks; i++){
			obj.values[i] = obj.min_value + (i * step);
		}

		// check if labels are defined and there are enough lables to 
		// display all the ticks. If not simply copy values as lables.
		if (!obj.labels || obj.labels == null){
			obj.labels = new Array();
		}
		
		if (obj.labels.length < obj.values.length) {
			for(i=obj.labels.length; i< obj.values.length; i++){
				obj.labels[i] = obj.min_value + (i * step) + "";
			}
		}
		
		
		
	}

	// now write out all the bits

	slider_render_scale(obj);
	slider_render_pane(obj);

	if ( obj.tick_tabs == null )	// calculate tabs between ticks
	{
	    obj.tick_tabs = (obj.scale_width-obj.tick_width) / (obj.ticks-1.0);
	}

	if (obj.show_ticks){
		for (i=0; i<obj.ticks; i++)	// draw ticks and labels
		{
		    slider_render_tick(i, obj);
		    slider_render_label(i, obj);
		}
	}

	slider_render_stylus_up(obj);
	slider_render_stylus_down(obj);

	// Install event handlers

	if (obj.interactive == true)
	{
	    if (moz || dom2)
	    {
		span = getElementById(obj.span_id);
		span.addEventListener("mousedown",slider_stylus_mousedown, 0);
		span.addEventListener("mouseup",slider_stylus_mouseup, 0);
		span.addEventListener("mousemove",slider_stylus_mousemove, 0);
	    }
	    if ( ie4 || ie5 || ie6 )
	    {
		span = all(obj.span_id);
		span.onmousedown = slider_stylus_mousedown;
		span.onmouseup = slider_stylus_mouseup;
		span.onmousemove = slider_stylus_mousemove;
	    }
	    if ( nn4 )
	    {
		span = layers[obj.span_id];
		span.captureEvents(Event.MOUSEDOWN|Event.MOUSEUP|Event.MOUSEMOVE);
		span.onMouseDown = slider_stylus_mousedown;
		span.onMouseUp = slider_stylus_mouseup;
		span.onMouseMove = slider_stylus_mousemove;
		window.document.onMouseMove = null;
	    }
	}
    }
    
    slider_set_value(obj);
}

// ---------------------------------------------------------------------
// render the scale "slot" or line
function slider_render_scale(obj)
{
    with (window.document) {
    write_slider_html(obj,"<span " +
    	"id=\"" + obj.span_id + "scale\" " +
		"style=\"" +
		    "z-index:1; margin:0; padding:0; " +
		    //"position: absolute; " +
		    "top:" + (obj.top + (obj.stylus_height/2) - (obj.scale_height/2)) + "px; " +
		    "left:" + obj.left + "px; " +
		"\" >"
		+
		
		"<img " +
		"src=\""+obj.scale_image+"\" " +
		"height=\"" + obj.scale_height + "\" " +
		"width=\"" + obj.scale_width + "\" " +
		"/>"

		+
		
		"</span>");
    }
}

// ---------------------------------------------------------------------
// Background clickable span used for all mouse input
// There is a hack here for NS 4.x - neither ID nor NAME
// are accessable from event handlers, so we tack the ID onto
// the end of the src attribute. Still a valid URL and doesn't break NN 4.
// If we don't do this, we can't tell which slider it is.
function slider_render_pane(obj)
{
    with (window.document) {
	write_slider_html(obj,"<span " +
		    "id=\"" + obj.span_id + "\" " +
		    "style=\"" +
    			"z-index:10; margin:0; padding:0; " +
		        "position: absolute; " +
			//"top: " + obj.top + "px; " +
			"left: " + (obj.left - obj.stylus_width/2) + "px; " +
	    "\" >" 
		+
		"<img " +
		    "id=\"" + obj.span_id + "_pane\" " +
		    ( nn4 ? "src=\""+obj.pane_image+"#"+obj.span_id+"\" "
		          : "src=\""+obj.pane_image+"\" "
		    ) +
		    "height=\"" + (obj.stylus_height + obj.tick_height + obj.label_size) + "\" " +
		    "width=\"" + (obj.scale_width+obj.stylus_width) + "\" " +
		    "/>"
		+
		"</span>");
    }
}

// ---------------------------------------------------------------------
// a mark along the scale
function slider_render_tick(i,obj)
{
    with (window.document) {
	write_slider_html(obj,"<span " +
		    "style=\"" +
			"z-index:1;" +
			"position: absolute; " +
			//"top:" + (obj.top + obj.stylus_height) + "px; " +
			"left:" + (obj.left + i*obj.tick_tabs) + "px; " +
			"font-size:" + obj.tick_width + "px; " +
		    "\">" 
		    +
		    "<img " +
		    "src=\"" + obj.tick_image + "\" " +
		    "height=\"" + obj.tick_height + "\" " +
		    "width=\"" + obj.tick_width + "\" " +
		    "/>"
			+
			"</span>");
    }
}

// ---------------------------------------------------------------------
// a label for one of the tick marks
function slider_render_label(i,obj)
{
   var label_style = "z-index:1; padding:0;  :0;";

   with (window.document)
   {
	write_slider_html(obj,"<span " +
		    "style=\"" +
			"position: absolute; "+
			//"top:" + (obj.top + obj.stylus_height + obj.tick_height) + "px; " +
			"left:" + (obj.left + i*obj.tick_tabs) + "px; " +
			"font-size:" + obj.label_size + "px; " +
			((!nn4) ? "font-family:"+obj.label_font+"; " : "") +
			label_style + "\" " +
	       ">"  + obj.labels[i] + "</span>");
    }
}

// ---------------------------------------------------------------------
// the stylus on the scale line (the "claw" or "pointer")
function slider_render_stylus_up(obj)
{
  with (window.document) {
	write_slider_html(obj,"<span " +
		    "id=\"" + obj.span_id + "up" + "\" " +
		    "style=\"" +
			"z-index:2; " +
			"position: absolute; margin:0; padding:0; "+
			//"top:" + obj.top + "px; " +
			"left:" + (obj.left + obj.start_tick*obj.tick_tabs - obj.stylus_width/2) + "px; " +
		"\" >" + "<img " +
		( nn4 ? "src=\""+obj.stylus_up+"#"+obj.span_id+"up\" "
		      : "src=\""+obj.stylus_up+"\" "
		) +
		"height=\"" + obj.stylus_height + "\" " +
		"width=\"" + obj.stylus_width + "\" " +
		"/>" + "</span>");
    }
}

// ---------------------------------------------------------------------
// the highlighted stylus on the scale line
function slider_render_stylus_down(obj)
{
  with (window.document) {
	write_slider_html(obj,"<span " +
		    "id=\"" + obj.span_id + "down" + "\" " +
		    "style=\"" +
			"z-index:3; " +
			"position: absolute; margin:0; padding:0;"+
			( nn4 ? "visibility: hide; " : "visibility: hidden; ")+
		//	"top:" + obj.top + "px; " +
			"left:" + (obj.left + obj.start_tick*obj.tick_tabs - obj.stylus_width/2) + "px; " +
		"\" >" + "<img " +
		( nn4 ? "src=\""+obj.stylus_down+"#"+obj.span_id+"down\" "
		      : "src=\""+obj.stylus_down+"\" "
		) +
		"height=\"" + obj.stylus_height + "\" " +
		"width=\"" + obj.stylus_width + "\" " +
		"/>" + "</span>");
    }
}

// ---------------------------------------------------------------------
// event handler for 3 classes of browser
function slider_stylus_mousedown(obj)
{
    var i;
    var slider_name;

    if ( old )
    	return;

    if (moz || dom2)
    {
        slider_name = obj.currentTarget.id;
	document.getElementById(slider_name+"up").style.visibility = "hidden";
	document.getElementById(slider_name+"down").style.visibility = "visible";
	obj.stopPropagation();
	obj.preventDefault();
    }

    if ( ie4 || ie5 || ie6 )
    {
	// picks up the <img> tag as src.
	// picks up the z-index:0 tag if the <img> edge is reached
	with (window.event.srcElement)
	{
	    if ( id == parentElement.id + "_pane" )
	    {
	    	slider_name = parentElement.id;
	    }
	    else
	    {
	    	slider_name = window.document.activeElement.id;
	    }
	}

	document.all(slider_name+"up").style.visibility = "hidden";
	document.all(slider_name+"down").style.visibility = "visible";
	window.event.cancelBubble = true;
	window.event.returnValue = false;
    }

    if ( nn4 )
    {
	slider_name = obj.target.src;
	i = slider_name.indexOf("#",0);	// the NN 4.x hack
	slider_name = slider_name.substring(i+1,slider_name.length);

	window.document.layers[slider_name+"up"].visibility = "hide";
	window.document.layers[slider_name+"down"].visibility = "show";
    }

    sliding = true;

    return false;	// for nn4
}

// ---------------------------------------------------------------------
// event handler for 3 classes of browser
function slider_stylus_mousemove(obj)
{
    var slider_name = "";
    var config = null;
    var x = 0;
    var i = 0;

    if ( old || !sliding )
    	return;

    // find current location and slider data

    if (moz || dom2)
    {
        slider_name = obj.currentTarget.id;
	x = obj.clientX;
	obj.stopPropagation();
	obj.preventDefault();
    }
    if ( ie4 || ie5 || ie6 )
    {
	// picks up the <img> tag as src.
	// picks up the z-index:0 tag if the <img> edge is reached
	// picks up <html> if user move is very fast

	with (window.event.srcElement)
	{
	    if ( tagName == "html" )
	    {
	    	sliding = false;
	        return;		// very fast mouse swipe by user - do nothing
	    }
	    else if ( id == parentElement.id + "_pane" )
	    {
	    	slider_name = parentElement.id;
	    }
	    else
	    {
	    	slider_name = window.document.activeElement.id;
	    }
	}

	x = window.event.clientX;
	window.event.cancelBubble = true;
	window.event.returnValue = false;
    }
    if ( nn4 )
    {
	slider_name = obj.target.src;
	i = slider_name.indexOf("#",0);	// the  NN 4.x hack
	slider_name = slider_name.substring(i+1,slider_name.length);
	x = obj.pageX;
    }

    for (i=0; i<sliders.length; i++)
    {
	if (sliders[i].span_id == slider_name )
	{
	    config = sliders[i];
	}
    }

	//x -= config.stylus_width/2;		// left edge of stylus, not center
    x = slider_normalise(x, config);
    

    // set new location

    if (moz || dom2)
    {
	document.getElementById(slider_name+"up").style.left = x + "px";
	document.getElementById(slider_name+"down").style.left = x + "px";
    }
    if ( ie4 || ie5 || ie6 )
    {
        document.all(slider_name+"up").style.left = x + "px";
        document.all(slider_name+"down").style.left = x + "px";
    }
    if ( nn4 )
    {
	window.document.layers[slider_name+"up"].left = x;
	window.document.layers[slider_name+"down"].left = x;
    }


	if(config.realtime_update){
		// update the slider value as it moves
		slider_set_value(config);
	}

    return false;	// for nn4
}

// ---------------------------------------------------------------------
// event handler for 3 classes of browser
function slider_stylus_mouseup(obj)
{
    var slider_name;
    var x;

    if ( old || !sliding)
    	return;

    // find current location and slider data
    if (moz || dom2)
    {
        slider_name = obj.currentTarget.id;
	obj.stopPropagation();
	obj.preventDefault();
	x = obj.clientX;
    }

    if ( ie4 || ie5 || ie6 )
    {
	// picks up the <img> tag as src.
	// picks up the z-index:0 tag if the <img> edge is reached

	with (window.event.srcElement)
	{
	    if ( id == parentElement.id + "_pane" )
	    {
	    	slider_name = parentElement.id;
	    }
	    else
	    {
	    	slider_name = window.document.activeElement.id;
	    }
	}

	x = window.event.clientX;
	window.event.cancelBubble = true;
	window.event.returnValue = false;
    }

    if ( nn4 )
    {
	slider_name = obj.target.src;
	i = slider_name.indexOf("#",0);	// the NN 4.x hack
	slider_name = slider_name.substring(i+1,slider_name.length);
	x = obj.pageX;
    }

    for (i=0; i<sliders.length; i++)
    {
	if (sliders[i].span_id == slider_name )
	{
	    config = sliders[i];
	}
    }

    // calculate final slider position

    x = slider_normalise(x, config);
    x = slider_align(x, config);

    //x -= config.stylus_width/2;		// center, not edge of stylus

    // do final update to position
    if ( moz || dom2)
    {
	document.getElementById(slider_name+"up").style.left = x + "px";
	document.getElementById(slider_name+"down").style.left = x + "px";

	document.getElementById(slider_name+"up").style.visibility = "visible";
	document.getElementById(slider_name+"down").style.visibility = "hidden";
    }
    if ( ie4 || ie5 || ie6 )
    {
	document.all(slider_name+"up").style.left = x + "px";
	document.all(slider_name+"down").style.left = x + "px";

	document.all(slider_name+"up").style.visibility = "visible";
	document.all(slider_name+"down").style.visibility = "hidden";
    }

    if ( nn4 )
    {
	window.document.layers[slider_name+"up"].left = x;
	window.document.layers[slider_name+"down"].left = x;

	window.document.layers[slider_name+"up"].visibility = "show";
	window.document.layers[slider_name+"down"].visibility = "hide";
    }

    window.sliding = false;
    
    slider_set_value(config);
    return false;
}

// needed to figure out what is the parent elements absolute position
function getElementPosition(theElement){
  var posX = 0;
  var posY = 0;
  while(theElement != null){
    posX += theElement.offsetLeft;
    posY += theElement.offsetTop;
    theElement = theElement.offsetParent;
  }
                        		      
   return {x:posX,y: posY};
}


// ---------------------------------------------------------------------
// make sure position x is never beyond the allowed bounds of the slider
function slider_normalise(x,obj)
{
	var sliderScale = document.getElementById(obj.span_id + "scale");
	var pos = getElementPosition(sliderScale);

	x-= pos.x;

    var xmin, xmax;
    // calculate new stylus location

    xmin = obj.left;
    xmax = obj.left + obj.scale_width;
  
    x = ( x <= xmin ) ? xmin : x;
    x = ( x >= xmax ) ? xmax : x;

    return x;
}

// ---------------------------------------------------------------------
// if the slider isn't continuous==true , align x with a tick mark.
function slider_align(x,obj)
{
    var tab = 0;
    if (!obj.continuous)		// must align with a tick
    {
	while ( (x -= obj.tick_tabs) > obj.left - obj.tick_tabs/2 )
	{
	    tab++;
	}
	x = obj.left + tab * obj.tick_tabs;
    }
    return x;
}

// ---------------------------------------------------------------------
// copy the slider setting into a form field. Call this from your own place.
function slider_set_value(obj)
{
    var i = 0, x = 0, data = null;

    if (moz || dom2)
    {
		x = window.document.getElementById(obj.span_id+"up").style.left;
		x = x.substring(0,x.length-2) - 0;
    }

    if ( ie4 || ie5 || ie6 )
    {
        x = document.all(obj.span_id+"up").style.left;
		x = x.substring(0,x.length-2) - 0;
    }

    if ( nn4 )
    {
		x = window.document.layers[obj.span_id+"up"].left;
    }

    //x += obj.stylus_width/2;
    if (!obj.continuous)	// must be aligned with a tick
    {
        x -= obj.left;
		while ( (x-=obj.tick_tabs) >= 0 )
		{
		    i++;
		}
		data = obj.values[i];
    }
    else
    {
		i = (x*1.0 - obj.left) / obj.scale_width;
	    data = i * (obj.values[obj.ticks-1] - obj.values[0]) + obj.values[0];
    }

    window.document.forms[obj.form_id][obj.form_field_id].value
    	= data + "";
    	
    eval(obj.update_function + "()");	
}


function write_slider_html(sliderObj,html){
	var sliderDiv = document.getElementById(sliderObj.div_id);
	sliderDiv.innerHTML = sliderDiv.innerHTML  + html;
}