
// global variables used for color selects

var mouse_x;
var mouse_y;
var color_selects = new Array(0);




function color_select() {

  // current mouse position
  //this.mouse_x=0;
  //this.mouse_y=0;
  
  // current control position
  this.sv_image="";
  this.x=0;
  this.y=0;

  // current h,s,v
  //  hsv:  h = 0-360    s = 0 (gray) - 1.0 (pure color)   v = 0 (black) to 255 (white)
  this.hue_value=10;
  this.sat_value=100;
  this.val_value=0;

  // references to boxes
  this.color_select_box = new Object;     // the box around the entire color select
  this.h_select_box = new Object;         // the box around the hue control
  this.sv_select_box = new Object;        // the box around the sat-val control
  this.sv_select_box_bg = new Object      // the box that holds the background of the sat-val control
  this.color_box = new Object             // the box that holds the background of the sat-val control
  this.color_value_box = new Object       // the box that holds the background of the sat-val control

  // references to cursors
  this.hue_cursor = new Object;         
  this.sv_crosshair_horiz_cursor = new Object;
  this.sv_crosshair_vert_cursor = new Object;

  // used for mapping between mouse positions and color parameters
  this.hue_offset=0;
  this.sat_offset=0;
  this.val_offset=0;
  this.color_select_bounding_box = new Array(4);    // upper-left corner x, upper-left corner y, width, height

  // state information for the controls
  this.initialized=false;
  this.active=false;
  this.h_select_box_focus=false;
  this.sv_select_box_focus=false;

  // map methods
  this.show = show;
  this.hide = hide;
  this.toggle_color_select = toggle_color_select;
  this.select_disable = select_disable;
  this.sv_update = sv_update;
  this.sv_cursor_draw = sv_cursor_draw;
  this.hue_cursor_draw = hue_cursor_draw;
  this.cursor_to_color = cursor_to_color;
  this.hue_cursor_to_color = hue_cursor_to_color;
  this.unfocus = unfocus;
  this.sethsv = sethsv;
  this.setrgb = setrgb;
  this.update_color_box = update_color_box;
  
  // function to call each time the color is updated
  this.update_function="";



  // these functions are tied to events (usually).
  // they are the entry points for whatever color_select does

  function show()
  {
    // alert ("show color select");
    this.color_select_bounding_box = new Array;
    
    // in mozilla, insert the saturation-value background image
    if (!document.all)   
      this.sv_select_box.style.backgroundImage="url('"+this.sv_image+"')";
    
    this.color_select_box.style.left = this.x + "px";
    this.color_select_box.style.top = this.y + "px";
    this.color_select_box.style.display = "block";
    this.color_select_box.style.visibility = "visible";
    
    this.sat_offset = docjslib_getRealTop(this.sv_select_box);
    this.val_offset = docjslib_getRealLeft(this.sv_select_box);
    this.hue_offset = docjslib_getRealTop(this.h_select_box);
  
    this.color_select_bounding_box[0]=this.x;
    this.color_select_bounding_box[1]=this.y;
    this.color_select_bounding_box[2]=300;
    this.color_select_bounding_box[3]=300;
    
    this.sv_cursor_draw();
    
    // position hue cursor
    this.hue_cursor.style.left = docjslib_getRealLeft(this.h_select_box) - docjslib_getRealLeft(this.color_select_box)-1;
    this.hue_cursor_draw();
    
    this.initialized=true;
    this.active=true;
    if (!this.color_select_box.style)
      alert ("color select box style not found!");
    
    this.update_color_box();
    //alert ("new hsv: "+ this.hue_cursor_pos +" "+this.sat_cursor_pos+" "+this.val_cursor_pos);
    //alert (this.x + " " + this.y);
  }
  
  function hide()
  {
    if (this.color_select_box)
      this.color_select_box.style.display = "none";
      
    this.active=false;
    this.unfocus();
  }
  
  function toggle_color_select()
  {
    if (this.active)
    {
      this.hide();
    }
    else
    {
      this.show();
    }
  }

      
  function select_disable() 
  {
    // This function is IE-only!  Moz doesn't need it, and ignores it.
    // When the mouse is dragged, IE attempts to select the DOM objects, 
    // which would be ok, but IE applies a dark highlight to the selection.  
    // This makes the color select look flickery and bad.
    // The solution is to disable IE's selection event when it occurs when the mouse is over
    // the color select.
    
    // But that's not quite enough.  We *do* want to be able to select the #FFFFF hex
    // value.  So we only disable IE selection when the mouse is moving the s-v or hue
    // cursor.
          
    if (this.h_select_box_focus || this.sv_select_box_focus)
      return true;
    else
      return false;
  }

  function hue_cursor_to_color() 
  {
    // map from the mouse position to the new hue value
    if (!this.h_select_box_focus) return;
    
    var new_hue_cursor_pos = mouse_y - this.hue_offset;
    
    // keep the value sensible
    if (new_hue_cursor_pos > 255)
      new_hue_cursor_pos=255;
    if (new_hue_cursor_pos < 0)
      new_hue_cursor_pos=0;
  
    this.hue_cursor_pos = new_hue_cursor_pos;
    this.hue_value = 360 - new_hue_cursor_pos/255*360;
    
    this.hue_cursor_draw();
    this.cursor_to_color();
      
  }
    
  function sv_update() 
  {
    // map from the mouse position to the new s-v values
    
    // might be possible to get rid of this
    if (!this.sv_select_box_focus) return;
    
    var new_sat_cursor_pos = mouse_y - this.sat_offset;
    var new_val_cursor_pos = mouse_x - this.val_offset;
    
    // keep the values sensible
    if (new_sat_cursor_pos > 255)
      new_sat_cursor_pos = 255;
    if (new_sat_cursor_pos < 0)
      new_sat_cursor_pos = 0;
      
    if (new_val_cursor_pos > 255)
      new_val_cursor_pos = 255;
    if (new_val_cursor_pos < 0)
      new_val_cursor_pos = 0;
    
    this.sat_cursor_pos = new_sat_cursor_pos;
    this.val_cursor_pos = new_val_cursor_pos;
    //window.status = this.hue_cursor_pos + ","+this.sat_cursor_pos + ","+this.val_cursor_pos +"("+this.sat_offset+ ","+this.val_offset+")";
    
    this.sv_cursor_draw();
    this.cursor_to_color();
    
    return;
  }

  function hue_cursor_draw()
  {
    if (!this.hue_cursor.style) return;
    if (!this.sv_select_box_bg.style) return;
  
    this.hue_cursor.style.top = this.hue_cursor_pos+1 + "px";

    this.hue_cursor.style.visibility = "visible";
    //this.cursor_to_color();
    
    // update sv_select_box background
    var hsvcolor = new Array(this.hue_value,1,255);
    var rgbcolor = hsv2rgb(hsvcolor);
    var new_color = "rgb("+rgbcolor[0]+", "+rgbcolor[1]+", "+rgbcolor[2]+")";
    this.sv_select_box_bg.style.background = new_color;
    //window.status="hue cursor draw! " + this.hue_cursor.style.left;
  }
  
  
  
  function sv_cursor_draw()
  {
    if (!this.sv_crosshair_horiz_cursor.style) return;
    if (!this.sv_crosshair_vert_cursor.style) return;
    
    // this is sort of a seat-of-the-pants algorithm for keeping the cursor
    // visible against the s-v background.  There are probably better methods.
    var cursor_color=this.val_cursor_pos;
    if (cursor_color==0) cursor_color=.001;
    cursor_color = Math.round(255/(cursor_color/30));
    if (cursor_color > 255) cursor_color = 255;
    if (cursor_color < 0) cursor_color = 0;
    
    this.sv_crosshair_vert_cursor.style.backgroundColor = "rgb("+cursor_color+","+cursor_color+","+cursor_color+")";
    this.sv_crosshair_horiz_cursor.style.borderColor = "rgb("+cursor_color+","+cursor_color+","+cursor_color+")";
    
    // place the s-v cursors.
    this.sv_crosshair_horiz_cursor.style.top = this.sat_cursor_pos+3 + "px";
    this.sv_crosshair_horiz_cursor.style.left = 2 + "px";
    this.sv_crosshair_horiz_cursor.style.visibility = "visible";
  
    this.sv_crosshair_vert_cursor.style.left = this.val_cursor_pos+3 + "px";
    this.sv_crosshair_vert_cursor.style.visibility = "visible";
    
    //this.cursor_to_color();
  
  }
    
  
  
  function cursor_to_color()
  {
    //calculate real h, s & v
    this.hue_value = ((255-this.hue_cursor_pos)/255*360);
    this.sat_value = (255 - this.sat_cursor_pos)/255;
    //this.sat_value = this.sat_cursor_pos;
    this.val_value = this.val_cursor_pos;
    //alert ("cursor_to_color: "+ this.hue_value +" "+this.sat_value+" "+this.val_value);

    this.update_color_box();
  }
  
  
  function unfocus() 
  {
    this.h_select_box_focus=false;
    this.sv_select_box_focus=false;
  }


  function setrgb(c)
  {
  
    var rgb = "";
    //  hsv:  h = 0-360    s = 0 (gray) - 1.0 (pure color)   v = 0 (black) to 255 (white)
    if (c.match(/#([0-9]|[A-F]){6}/i))  // valid hex #color?
    {
      rgb = hex2rgb(c.substring(1,7));
    }
    else if (c.match(/#([0-9]|[A-F]){3}/i))  // valid hex #color?
    {
      rgb = c.substring(1,2) + c.substring(1,2) +
            c.substring(2,3) + c.substring(2,3) +
            c.substring(3,4) + c.substring(3,4);
    }
    else return false;
      
     
    
    //alert ("hex -> rgb: "+ rgb[0] +" "+rgb[1]+" "+rgb[2]);
    
    hsv = rgb2hsv(rgb);
    
    //alert ("rgb -> hsv: "+ hsv[0] +" "+hsv[1]+" "+hsv[2]);
    
    this.sethsv(hsv[0],hsv[1],hsv[2]);
    
    //rgb_again = hsv2rgb(hsv);
    //alert ("hex -> rgb: "+ rgb[0] +" "+rgb[1]+" "+rgb[2]+
    //       "\nrgb -> hsv: "+ hsv[0] +" "+hsv[1]+" "+hsv[2]+
    //       "\nrgb -> hsv -> rgb: "+ rgb_again[0] +" "+rgb_again[1]+" "+rgb_again[2]);
    return true;
  }
  
  
  function sethsv(h, s, v)
  {
    var hsvcolor;
    
    this.hue_value = h;  
    this.sat_value = s;  
    this.val_value = v;  
   
    this.hue_cursor_pos = (360 - this.hue_value)/360*255;
    this.sat_cursor_pos = Math.round(255 - 255*this.sat_value);
    this.val_cursor_pos = this.val_value;
    
    this.update_color_box();    
  }
  
  
  function update_color_box()
  {
    var hsvcolor = new Array(this.hue_value,this.sat_value,this.val_value);
    
    // make them into an rgb color
    var rgbcolor = hsv2rgb(hsvcolor);
    
    //rgbcolor[0] = Math.round(rgbcolor[0]/255*100);
    //rgbcolor[1] = Math.round(rgbcolor[1]/255*100);
    //rgbcolor[2] = Math.round(rgbcolor[2]/255*100);
    
    var new_color = "rgb("+rgbcolor[0]+","+rgbcolor[1]+","+rgbcolor[2]+")";
    //alert ("rgb: "+ rgbcolor[0] +" "+rgbcolor[1]+" "+rgbcolor[2]);
    
    
    // and in hex
    var hexcolor="#"+baseconverter(rgbcolor[0],10,16,2)+baseconverter(rgbcolor[1],10,16,2)+baseconverter(rgbcolor[2],10,16,2);
    setTimeout(this.update_function+"(\""+hexcolor+"\")",100);
    
    // display it!
    if (this.color_value_box)
      this.color_value_box.innerHTML = hexcolor;
    
    if (this.color_value_box.style)
      this.color_box.style.background = new_color;
  }
      
  // push the new color select object onto the
  // global array of color select objects.
  
  // for some reason, the array.push() method 
  // doesn't work with objects, only with primitives.
  
  color_selects[color_selects.length] = this;
}

function color_select_mousedown() {
  for (var l1=0;l1<color_selects.length;l1++)
  {
    var ob=color_selects[l1];
    if (!ob.active) continue;
  
    // if the mousedown is outside the color_select_box, close it.
    if  (mouse_x < ob.color_select_bounding_box[0] ||
        mouse_y < ob.color_select_bounding_box[1] ||
        mouse_x > (ob.color_select_bounding_box[0]+ob.color_select_bounding_box[2]) ||
        mouse_y > (ob.color_select_bounding_box[1]+ob.color_select_bounding_box[3]))
    {
      //ob.hide_color_select();
      setTimeout("color_select_hide("+l1+")",100);
    }
  }
}

function color_select_hide(num)
{
  var ob=color_selects[num];
  ob.hide();
}

function color_select_hideall()
{
  //alert("hiding all color selects!");
  for (var l1=0;l1<color_selects.length;l1++)
  {
    var ob=color_selects[l1];
    ob.hide();
  }
}


function color_select_mouseup() {
  
  for (var l1=0;l1<color_selects.length;l1++)
  {
    ob=color_selects[l1];
    ob.unfocus();
    // if the mouseup is outside the color_select_box, close it.
    //if  (mouse_x < ob.color_select_bounding_box[0] ||
    //    mouse_y < ob.color_select_bounding_box[1] ||
    //    mouse_x > (ob.color_select_bounding_box[0]+ob.color_select_bounding_box[2]) ||
    //    mouse_y > (ob.color_select_bounding_box[1]+ob.color_select_bounding_box[3]))
    //{
    //  ob.hide();
    //}
  }
}

function get_mouse_coords(e) { 
  if (window.event) // IE
  {
    mouse_x=window.event.clientX+document.body.scrollLeft;
    mouse_y=window.event.clientY+document.body.scrollTop;
  }
  else              // moz
  { 
    mouse_x=e.pageX;
    mouse_y=e.pageY;
  }
}

function color_select_update() {
  for (var l1=0;l1<color_selects.length;l1++)
  {
    ob=color_selects[l1];
    ob.sv_update();
    ob.hue_cursor_to_color();
  }
}


// below are miscellanous conversion functions.  Some of them 
// are modified versions of someone else's code.

function findowner(evt)
{
  if (evt.target)
    return evt.target;
  else if (evt.srcElement)
    return evt.srcElement;
  else
    return null;
}


function baseconverter (number,ob,nb,desired_length) 
{
	// Created 1997 by Brian Risk.  http://members.aol.com/brianrisk
  number += "";  // convert to character, or toUpperCase will fail on some browsers
	number = number.toUpperCase();
	var list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var dec = 0;
	for (var i = 0; i <=  number.length; i++) 
		dec += (list.indexOf(number.charAt(i))) * (Math.pow(ob , (number.length - i - 1)));
	number = "";
	var magnitude = Math.floor((Math.log(dec))/(Math.log(nb)));
	for (var i = magnitude; i >= 0; i--) 
  {
    //--  stupid nedit, thinks the decrement above is a html commment.
		var amount = Math.floor(dec/Math.pow(nb,i));
		number = number + list.charAt(amount); 
		dec -= amount*(Math.pow(nb,i));
	}
  
  var length=number.length;
  if (length<desired_length)
    for (var i=0;i<desired_length-length;i++)
      number = "0"+number;
  
	return number;
}

function docjslib_getRealTop(imgElem) {
  yPos = imgElem.offsetTop;
  tempEl = imgElem.offsetParent;
  while (tempEl != null) {
    yPos += tempEl.offsetTop;
    tempEl = tempEl.offsetParent;
  }
  return yPos;
}

function docjslib_getRealLeft(imgElem) {
  xPos = imgElem.offsetLeft;
  tempEl = imgElem.offsetParent;
    while (tempEl != null) {
      xPos += tempEl.offsetLeft;
      tempEl = tempEl.offsetParent;
    }
  return xPos;
}

// RGB, each 0 to 255
//  hsv:  h = 0-360    s = 0 (gray) - 1.0 (pure color)   v = 0 (black) to 255 (white)
function rgb2hsv(rgb) {
  var r = rgb[0];
  var g = rgb[1];
  var b = rgb[2];

  var h;
  var s;
	var v = Math.max(Math.max(r, g), b);
	var min = Math.min(Math.min(r, g), b);
  var delta = v - min;

   // Calculate saturation: saturation is 0 if r, g and b are all 0
  if (v == 0)
    s = 0
  else 
    s = delta / v;
    
  if (s==0)
    h=0;  //achromatic.  no hue
  else
  {
    if (r==v)            // between yellow and magenta [degrees]
      h=60*(g-b)/delta;
    else if (g==v)       // between cyan and yellow
      h=120+60*(b-r)/delta;
    else if (b==v)       // between magenta and cyan
      h=240+60*(r-g)/delta;
  }  
  
  if (h<0)
    h+=360;
    
  return new Array(h,s,v);
}

// RGB, each 0 to 255
//  hsv:  h = 0-360    s = 0 (gray) - 1.0 (pure color)   v = 0 (black) to 255 (white)
function hsv2rgb(hsv) {
  var h = hsv[0];
  var s = hsv[1];
  var v = hsv[2];
  
  var r;
  var g;
  var b;
  
  if (s==0) // achromatic (grey)
    return new Array(v,v,v);
  
  var htemp;
  
  if (h==360)
    htemp=0;
  else
    htemp=h;
    
  htemp=htemp/60;
  var i = Math.floor(htemp);   // integer <= h
  var f = htemp - i;           // fractional part of h

  var p = v * (1-s);
  var q = v * (1-(s*f));
  var t = v * (1-(s*(1-f)));
 
  if (i==0) {r=v;g=t;b=p;}
  if (i==1) {r=q;g=v;b=p;}
  if (i==2) {r=p;g=v;b=t;}
  if (i==3) {r=p;g=q;b=v;}
  if (i==4) {r=t;g=p;b=v;}
  if (i==5) {r=v;g=p;b=q;}

  r=Math.round(r);
  g=Math.round(g);
  b=Math.round(b);

  return new Array(r,g,b);

}

function hex2rgb(h) {
  // RGB, each 0 to 255
  
  var r = Math.round(parseInt(h.substring(0,2),16));
  var g = Math.round(parseInt(h.substring(2,4),16));
  var b = Math.round(parseInt(h.substring(4,6),16));
  
	var results = new Array(r,g,b);
  return results;
}

function move_test()
{
  alert("move test");
}

function color_select_unfocus()
{
  for (var l1=0;l1<color_selects.length;l1++)
  {
    ob=color_selects[l1];
    ob.unfocus();
  }
}

function cs_select_disable()
{
  for (var l1=0;l1<color_selects.length;l1++)
  {
    ob=color_selects[l1];
    if (ob.select_disable())
      return false;
  }
}

function cs_hookup()
{

  // hook up the color select to the appropriate browser events.
  if (document.attachEvent)                 // IE uses proprietary event model
  {
    document.attachEvent('onmousedown',color_select_mousedown);
    document.attachEvent('onmouseup',color_select_mouseup);
    document.attachEvent('onmouseup',color_select_unfocus);
    document.attachEvent('onmousemove',get_mouse_coords);
    document.attachEvent('onmousemove',color_select_update);
    document.attachEvent('onselectstart',cs_select_disable);  // this event is IE-only
  }
  else                                      // Moz uses W3C DOM event model
  {
    document.addEventListener('resize',color_select_mousedown, false);
    document.addEventListener('mousedown', color_select_mousedown, false);
    document.addEventListener('mouseup', color_select_mouseup, false);
    document.addEventListener('mousemove', get_mouse_coords, false);
    document.addEventListener('mousemove', color_select_update, false);
    document.addEventListener('resize', color_select_hideall, false);
  }
}




