<!--
/******************************************************************************
  Fade Color Bar script (V2)
  =====================
  Generate dynamic gradiant colored bar using tables.
  
  Color Options:
  - RGB     - Basic 2 colors blending using RGB algorithm
  - HSL     - Color blending using HSL algorithm (go through Hue color ranges)
  - Rainbow - Rainbow scale


  ----- USAGE ---------------
  In html head:
  <script src="/script/fadeColor.js" type="text/javascript" language="javascript"></script>

  Examples:
  RGB:-
	<script language="JavaScript">
		fadeColorBar({fromCol:'000000', toCol:'CCCCCC', fadeParts:'50', barWidth:'760', barHeight:'2', topPad:'10', bottomPad:'5'})
	</script>
  
  HSL:-
  	fadeColorBar({fromCol:'FF0000', toCol:'8000FF', fadeParts:'11', barWidth:'737', barHeight:'3', topPad:'3', bottomPad:'3', fadeStyle:'HSL'})
  
  Rainbow:-
  	fadeColorBar({fromCol:'FF0000', rainbowScale:'1', fadeParts:'10', barWidth:'1000', barHeight:'3', topPad:'3', bottomPad:'3', fadeStyle:'Rainbow'})
  
  Vertical:-
  	fadeColorBarV({fromCol:'FF0000', rainbowScale:'1', fadeParts:'90', barWidth:'8', barHeight:'100', leftPad:'3', rightPad:'3', topPad:'10', bottomPad:'10', fadeStyle:'Rainbow'})
  
  Text:-
  	fadeColorText({fromCol:'FF0000', rainbowScale:'1', fadeParts:'12', fadeStyle:'Rainbow'})



  ----- Main Functions for External Use ---------------

  Fade Color Bar Functions:
  - fadeColorBar(oArg) (Horizontal)
      fromCol, toCol, fadeParts, barWidth, barHeight, topPad, bottomPad,
      rainbowScale, fadeStyle, colorCode, disableWrite
  - fadeColorBarV(oArg) (Vertical)
      fromCol, toCol, fadeParts, barWidth, barHeight, topPad, bottomPad, leftPad, rightPad,
      rainbowScale, fadeStyle, colorCode, disableWrite
  - fadeColorText(oArg) (for debugging color code)
      fromCol, toCol, fadeParts, rainbowScale, fadeStyle

  ----- Auxiliary Functions --------------- 

  Hex Functions:
  - isHex(theVal, place)
  - addHash(value)
  - removeHash(value)
  - Dec2Hex(value, place)
  - Hex2Dec(value, place)
  - padHex(value, place)
  
  RGB/HSL Conversion Functions: (Auxiliary)
  - HSL2RGB(hue, saturation, luminance)
  - RGB2HSL(red, green, blue)

  Fade Color Functions:
  - fadeColor( fromCol, toCol, fadePortion )
  - fadeColorHSL( fromCol, toCol, fadePortion )
  - rainbowColor( fromCol, rainbowScale, fadePortion )


  ----- HISTORY ---------------
  2005-02-23 - non-spacer version; (backward compatible, parameter is ignored) (V3)
  2004-03-29 - Added Vertical Bar; (V2)
  2003-12-31 - Added Horizontal Bar + fadeColorText; (V1)
  2003-12-30 - Completed Fade Color Functions;
  2003-12-10 - Started;
  
  by JK (CGST)
  
  --------------------
  "fadeColor" function is modified from "fadeColour" by Mark Wilton-Jones (23/06/2002)
  originated from http://www.fjt2.net/gate/gb/www.howtocreate.co.uk/jslibs/

******************************************************************************/


/*--Hex Functions------------------------------------------------------------*/

//function isHex(theVal) { return (/^#?[0-9A-F]{6}$/i).test(theVal+""); }
function isHex(theVal, place) {
  if (place == undefined || place <= 0) {
    re = new RegExp("^#?[0-9A-F]*$","i");
  } else {
    re = new RegExp("^#?[0-9A-F]{" + place + "}$","i");
  }
  return re.test(theVal+"");
}

function addHash(value) {
// remove first char if it's "#", else do nothing
  return "#" + value;
}
function removeHash(value) {
// remove first char if it's "#", else do nothing
  if (value.indexOf("#") == 0) {
    return value.substr(1);
  } else {
    return value;
  }
}

//function Dec2Hex(n) { return parseInt(n,10).toString(16); }
//function Hex2Dec(n) { return parseInt(removeHash(n),16); }
function Dec2Hex(value, place) {
  if (place == undefined || place < 2) { place = 8; }

  var str = parseInt(value,10).toString(16);
  if (str.charAt(0) == "-") {
    var neg1 = "FF";
    while (neg1.length < place) {
      neg1 += "F";
    }
    str = str.substr(1);
    str = parseInt(neg1,16) - parseInt(str,16) + 1;
    str = str.toString(16);
  }
  return padHex(str,2);
}
function Hex2Dec(value, place) {
  var str = removeHash(value);
  if (place == undefined || place < 2 || str.length != place) {
    return parseInt(str,16);
  }
  if (str.charAt(0) == "F") {
    var neg1 = "FF";
    while (neg1.length < place) {
      neg1 += "F";
    }
    str = parseInt(neg1,16) - parseInt(str,16) + 1;
    return (0 - str);
  } else {
    return parseInt(str,16);
  }
}

function padHex(value, place) {
// pad Hex(value) to number of 'place'
// if 'place' is not set or = 0, then there will be no padding
  if (place == undefined || place <= 0) { place = 1; }
  
  var rtnString = value.toString (16);
  while (rtnString.length < place) {
    rtnString = "0" + rtnString;
  }
  return rtnString.toUpperCase();
}


/*--RGB/HSL------------------------------------------------------------------*/
//
//  RGB - Red/Green/Blue (255/255/255)
//  HSL - Hue/Saturation/Luminance (360/100%/100%) => (240/240/240)
//

function HSL2RGB(hue, saturation, luminance) {
  this.hexColor = function () {
    return '#' + padHex (this.red,2) + padHex (this.green,2) + padHex (this.blue,2);
  }
  this.computeRGB = function () {
    var redValue, greenValue, blueValue;

    //  Figure hue value ( R:0 | Y:40 | G:80 | C:120 | B:160 | M:200 | R:240 )
    if (this.hue <= 40) {
      redValue = 255;
      grnValue = 255 * this.hue / 40;
      bluValue = 0;
    } else if (this.hue<= 80) {
      redValue = 255 * (80 - this.hue) / 40;
      grnValue = 255;
      bluValue = 0;
    } else if (this.hue <= 120) {
      redValue = 0;
      grnValue = 255;
      bluValue = 255 * (this.hue - 80) / 40;
    } else if (this.hue <= 160) {
      redValue = 0;
      grnValue = 255 * (160 - this.hue) / 40;
      bluValue = 255;
    } else if (this.hue <= 200) {
      redValue = 255 * (this.hue - 160) / 40;
      grnValue = 0;
      bluValue = 255;
    } else { // if (this.hue <= 240) {
      redValue = 255;
      grnValue = 0;
      bluValue = 255 * (240 - this.hue) / 40;
    }

    //  Adjust for saturation ( Color:240 | Gray:0 )
    redValue = ((240 - this.saturation) * 127 + this.saturation * redValue) / 240;
    grnValue = ((240 - this.saturation) * 127 + this.saturation * grnValue) / 240;
    bluValue = ((240 - this.saturation) * 127 + this.saturation * bluValue) / 240;

    //  Adjust for luminance ( Black:0 | Color:120 | White:240 )
    if (this.luminance < 120) {
      redValue = this.luminance * redValue / 120;
      grnValue = this.luminance * grnValue / 120;
      bluValue = this.luminance * bluValue / 120;
    } else {
      redValue = (255 * (this.luminance - 120) + (240 - this.luminance) * redValue) / 120;
      grnValue = (255 * (this.luminance - 120) + (240 - this.luminance) * grnValue) / 120;
      bluValue = (255 * (this.luminance - 120) + (240 - this.luminance) * bluValue) / 120;
    }

    //  Make integers
    this.red = Math.floor (redValue + 0.5);
    this.green = Math.floor (grnValue + 0.5);
    this.blue = Math.floor (bluValue + 0.5);
  }
  //----- main -----//
  if (saturation == undefined && luminance == undefined && isHex(hue,6)) {
    var temp = removeHash(hue);
    if (temp.length == 6) {
      this.hue        = Math.min (240, Hex2Dec(temp.substr(0,2)));
      this.saturation = Math.min (240, Hex2Dec(temp.substr(2,2)));
      this.luminance  = Math.min (240, Hex2Dec(temp.substr(4,2)));
    } else {
      alert("HSL2RGB: Invalid Input: '" + hue + "', '" + saturation + "', '" + luminance + "'");
      return false;
    }
  } else {
    this.hue        = Math.max (0, Math.min (240, hue));
    this.saturation = Math.max (0, Math.min (240, saturation));
    this.luminance  = Math.max (0, Math.min (240, luminance));
  }
  this.computeRGB ();
  return this.hexColor();
}

function RGB2HSL(red, green, blue) {
  this.hexColor = function () {
    return '#' + padHex (this.hue,2) + padHex (this.saturation,2) + padHex (this.luminance,2);
  }
  this.computeHSL = function () {
    var h_value = 0;
    var s_value = 0;
    var l_value = 0;

    //  Calculate Luminance ( Black:0 | Color:120 | White:240 )
    var maxColor = Math.max (this.red, Math.max(this.green,this.blue));
    var minColor = Math.min (this.red, Math.min(this.green,this.blue));
    l_value = Math.round((maxColor + minColor)/2 * 240/255);

    // if not Gray (since H=S=0 for Gray)
    if (maxColor != minColor) {
      //  Calculate Saturation ( Color:240 | Gray:0 )
      if (l_value < 120) {
        s_value = (maxColor-minColor)/(maxColor+minColor) * 240;
      } else {
        s_value = (maxColor-minColor)/(255*2-maxColor-minColor) * 240;
      }

      //  Calculate Hue ( R:0 | Y:40 | G:80 | C:120 | B:160 | M:200 | R:240 )
      if (this.red == maxColor) {
        h_value = (this.green-this.blue)/(maxColor-minColor)*40;
        h_value = (h_value < 0 ? (240 - h_value) : h_value);  // adjust for negative
      } else if (this.green == maxColor) {
        h_value = (this.blue-this.red)/(maxColor-minColor)*40 +80;
      } else { // if (this.blue == maxColor) {
        h_value = (this.red-this.green)/(maxColor-minColor)*40 +160;
      }
    }
    //  Make integers
    this.hue = Math.floor (h_value + 0.5);
    this.saturation = Math.floor (s_value + 0.5);
    this.luminance = Math.floor (l_value + 0.5);
  }
  //----- main -----//
  if (green == undefined && blue == undefined && isHex(red,6)) {
    var temp = removeHash(red);
    if (temp.length == 6) {
      this.red   = Hex2Dec(temp.substr(0,2));
      this.green = Hex2Dec(temp.substr(2,2));
      this.blue  = Hex2Dec(temp.substr(4,2));
    } else {
      alert("RGB2HSL: Invalid Input: '" + red + "', '" + green + "', '" + blue + "'");
      return false;
    }
  } else {
    this.red   = Math.max (0, Math.min (255, red));
    this.green = Math.max (0, Math.min (255, green));
    this.blue  = Math.max (0, Math.min (255, blue));
  }
  this.computeHSL ();
  return this.hexColor();
}

/*--Fade Color---------------------------------------------------------------*/
function fadeColor( fromCol, toCol, fadePortion ) {
  if( fadePortion < 0 || fadePortion > 1 || isNaN( fadePortion ) ) {
    window.defaultStatus = 'Fatal error: fadeColor passed invalid portion - must be between 0 and 1';
    return '#000000';
  }
  if (!isHex(fromCol,6) || !isHex(toCol,6)) {
    window.defaultStatus = 'Fatal error: fadeColor passed invalid rrggbb hex color value';
    return '#000000';
  }
  fromCol = removeHash(fromCol);
  toCol = removeHash(toCol);
  for( var x = 0, oF = [], oT = [], oP = [], oH = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']; x < 3; x++ ) {
    oF[x] = eval( '0x' + fromCol.substring( 2 * x, ( 2 * x ) + 2 ) );
    oT[x] = eval( '0x' + toCol.substring( 2 * x, ( 2 * x ) + 2 ) );
    oP[x] = Math.round( oF[x] + ( ( oT[x] - oF[x] ) * fadePortion ) );
    oP[x] = oH[ ( oP[x] - ( oP[x] % 16 ) ) / 16 ] + oH[ oP[x] % 16 ];
  }
  return '#' + oP.join('');
}

function fadeColorHSL( fromCol, toCol, fadePortion ) {
  if( fadePortion < 0 || fadePortion > 1 || isNaN( fadePortion ) ) {
    window.defaultStatus = 'Fatal error: fadeColorHSL passed invalid portion - must be between 0 and 1';
    return '#000000';
  }
  if (!isHex(fromCol,6) || !isHex(toCol,6)) {
    window.defaultStatus = 'Fatal error: fadeColorHSL passed invalid rrggbb hex color value';
    return '#000000';
  }
  var from_hsl  = removeHash(RGB2HSL(fromCol));
  var to_hsl    = removeHash(RGB2HSL(toCol));
  for( var x = 0, oF = [], oT = [], oP = [], oH = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']; x < 3; x++ ) {
    oF[x] = eval( '0x' + from_hsl.substring( 2 * x, ( 2 * x ) + 2 ) );
    oT[x] = eval( '0x' + to_hsl.substring( 2 * x, ( 2 * x ) + 2 ) );
    oP[x] = Math.round( oF[x] + ( ( oT[x] - oF[x] ) * fadePortion ) );
    oP[x] = oH[ ( oP[x] - ( oP[x] % 16 ) ) / 16 ] + oH[ oP[x] % 16 ];
  }
  return HSL2RGB(oP.join(''));
}

function rainbowColor( fromCol, rainbowScale, fadePortion ) {
  if( fadePortion < 0 || fadePortion > 1 || isNaN( fadePortion ) ) {
    window.defaultStatus = 'Fatal error: rainbowColor passed invalid portion - must be between 0 and 1';
    return '#000000';
  }
  if( rainbowScale < 0 || isNaN(rainbowScale) ) {
    window.defaultStatus = 'Fatal error: rainbowColor passed invalid rainbowScale - must be greater than 0';
    return '#000000';
  }
  if (!isHex(fromCol,6)) {
    window.defaultStatus = 'Fatal error: rainbowColor passed invalid rrggbb hex color value';
    return '#000000';
  }
  var from_hsl  = removeHash(RGB2HSL(fromCol));
  var from_h    = Hex2Dec(from_hsl.substr(0,2));

  return HSL2RGB(Dec2Hex((from_h + (240 * rainbowScale * fadePortion)) % 240) + from_hsl.substr(2,4));
}

function fadeColorBar(oArg) {
  //fromCol, toCol, fadeParts, barWidth, barHeight, topPad, bottomPad
  //rainbowScale, fadeStyle, colorCode, disableWrite
  var fromCol = 'fromCol' in oArg? oArg.fromCol : "#000000";  //6 digits HEX String (with optional #)
  var toCol = 'toCol' in oArg? oArg.toCol : "#FFFFFF";        //6 digits HEX String (with optional #); not used with "RAINBOW"
  var fadeParts = 'fadeParts' in oArg? oArg.fadeParts : 1;    //integer >0
  var barWidth = 'barWidth' in oArg? oArg.barWidth : "100%";  //Integer/Percent String
  var barHeight = 'barHeight' in oArg? oArg.barHeight : 1;    //Integer
  var topPad = 'topPad' in oArg? oArg.topPad : 0;             //Integer
  var bottomPad = 'bottomPad' in oArg? oArg.bottomPad : 0;    //Integer
  //var spacer = 'spacer' in oArg? oArg.spacer : "spacer.gif";  //1x1 pixel transparent gif location
  var rainbowScale = 'rainbowScale' in oArg? oArg.rainbowScale : 1;     //length of the rainbow scale
  var fadeStyle = 'fadeStyle' in oArg? oArg.fadeStyle : "RGB";          //Fade Style: "RGB", "HSL", "RAINBOW"
  var colorCode = 'colorCode' in oArg? oArg.colorCode : false;          //Insert Color Code Text
  var disableWrite = 'disableWrite' in oArg? oArg.disableWrite : false; //Disable document.write and only return the string
  
  var eachWidth
  var outColor
  var outputStr = ""
  
  // make sure fadeParts is at most 1/3 of barWidth, since minimum table width is 3px
  if (barWidth.indexOf("%") == -1) {
    fadeParts = Math.max(1, Math.min(Math.floor(barWidth/3),fadeParts));
  }
  
  outputStr += '  <table width="' + barWidth + '" border="0" cellspacing="0" cellpadding="0">\n';
  if (topPad != 0) {
    outputStr += '    <tr><td colspan="' + fadeParts + '" height="' + topPad + '"></td></tr>\n';
  }

  outputStr += '    <tr>\n';
  for (var y=0; y<fadeParts; y++) {
    // calculate each cell's width
    if (barWidth.indexOf("%") == -1) {
      eachWidth = Math.round((y+1)*barWidth/fadeParts) - Math.round(y*barWidth/fadeParts)
    } else {
      eachWidth = Math.round((y+1)*100/fadeParts) - Math.round(y*100/fadeParts);
      eachWidth += "%";
    }
    if (fadeStyle.toUpperCase() == "RAINBOW") {
      outColor = rainbowColor(fromCol, rainbowScale, y/fadeParts);
    } else if (fadeStyle.toUpperCase() == "HSL") {
      outColor = fadeColorHSL(fromCol, toCol, y/(fadeParts-1));
    } else {  // if (fadeStyle.toUpperCase() == "RGB") {
      outColor = fadeColor(fromCol, toCol, y/(fadeParts-1));
    }
//    outputStr += '      <td width="' + eachWidth + '%" bgcolor="'+ outColor +'">';
    outputStr += '      <td width="' + eachWidth + '" height="' + barHeight + '" bgcolor="'+ outColor +'">';
    if (colorCode) {
      outputStr += '' + outColor + '</td>\n';
    } else {
      outputStr += '</td>\n';
    }
  }
  outputStr += '    </tr>\n';

  if (bottomPad != 0) {
    outputStr += '    <tr><td colspan="' + fadeParts + '" height="' + bottomPad + '"></td></tr>\n';
  }
  outputStr += '  </table>\n';

  //alert(outputStr);
  if (!disableWrite) {
    document.write(outputStr);
  }
  return outputStr;
}

function fadeColorBarV(oArg) {
  //fromCol, toCol, fadeParts, barWidth, barHeight, topPad, bottomPad, leftPad, rightPad,
  //rainbowScale, fadeStyle, colorCode, disableWrite
  var fromCol = 'fromCol' in oArg? oArg.fromCol : "#000000";  //6 digits HEX String (with optional #)
  var toCol = 'toCol' in oArg? oArg.toCol : "#FFFFFF";        //6 digits HEX String (with optional #); not used with "RAINBOW"
  var fadeParts = 'fadeParts' in oArg? oArg.fadeParts : 1;    //integer >0
  var barWidth = 'barWidth' in oArg? oArg.barWidth : "100%";  //Integer/Percent String (Total width including paddings)
  var barHeight = 'barHeight' in oArg? oArg.barHeight : 1;    //Integer
  var topPad = 'topPad' in oArg? oArg.topPad : 0;             //Integer
  var bottomPad = 'bottomPad' in oArg? oArg.bottomPad : 0;    //Integer
  var leftPad = 'leftPad' in oArg? oArg.leftPad : 0;          //Integer - will be subtracted from barWidth
  var rightPad = 'rightPad' in oArg? oArg.rightPad : 0;       //Integer - will be subtracted from barWidth
  //var spacer = 'spacer' in oArg? oArg.spacer : "spacer.gif";  //1x1 pixel transparent gif location
  var rainbowScale = 'rainbowScale' in oArg? oArg.rainbowScale : 1;     //length of the rainbow scale
  var fadeStyle = 'fadeStyle' in oArg? oArg.fadeStyle : "RGB";          //Fade Style: "RGB", "HSL", "RAINBOW"
  var colorCode = 'colorCode' in oArg? oArg.colorCode : false;          //Insert Color Code Text
  var disableWrite = 'disableWrite' in oArg? oArg.disableWrite : false; //Disable document.write and only return the string
  
  var eachHeight
  var outColor
  var outputStr = ""

  // make sure fadeParts is at most = barHeight, since minimum table height is 1px
  fadeParts = Math.max(1, Math.min(barHeight,fadeParts));

  outputStr += '  <table width="' + barWidth + '" height="' + barHeight + '" border="0" cellspacing="0" cellpadding="0">\n';
  if (topPad != 0) {
    outputStr += '    <tr><td colspan="3" height="' + topPad + '"></td></tr>\n';
  }

  for (var y=0; y<fadeParts; y++) {
    // calculate each cell's height
    eachHeight = Math.round((y+1)*barHeight/fadeParts) - Math.round(y*barHeight/fadeParts)

    if (fadeStyle.toUpperCase() == "RAINBOW") {
      outColor = rainbowColor(fromCol, rainbowScale, y/fadeParts);
    } else if (fadeStyle.toUpperCase() == "HSL") {
      outColor = fadeColorHSL(fromCol, toCol, y/(fadeParts-1));
    } else {  // if (fadeStyle.toUpperCase() == "RGB") {
      outColor = fadeColor(fromCol, toCol, y/(fadeParts-1));
    }
    outputStr += '    <tr>\n';
    if (leftPad != 0 && y == 0) {
      outputStr += '    <td rowspan="' + fadeParts + '" width="' + leftPad + '"></td>\n';
    }
    outputStr += '      <td height="' + eachHeight + '" bgcolor="'+ outColor +'">';
    if (colorCode) {
      outputStr += '' + outColor + '</td>\n';
    } else {
      outputStr += '</td>\n';
    }
    if (rightPad != 0 && y == 0) {
      outputStr += '    <td rowspan="' + fadeParts + '" width="' + rightPad + '"></td>\n';
    }
    outputStr += '    </tr>\n';
  }
  
  if (bottomPad != 0) {
    outputStr += '    <tr><td colspan="3" height="' + bottomPad + '"></td></tr>\n';
  }
  outputStr += '  </table>\n';

  //alert(outputStr);
  if (!disableWrite) {
    document.write(outputStr);
  }
  return outputStr;
}

function fadeColorText(oArg) {
  //fromCol, toCol, fadeParts, rainbowScale, fadeStyle
  
  var fromCol = 'fromCol' in oArg? oArg.fromCol : "#000000";  //6 digits HEX String (with optional #)
  var toCol = 'toCol' in oArg? oArg.toCol : "#FFFFFF";        //6 digits HEX String (with optional #); not used with "RAINBOW"
  var fadeParts = 'fadeParts' in oArg? oArg.fadeParts : 1;    //integer >0
  var rainbowScale = 'rainbowScale' in oArg? oArg.rainbowScale : 1; //length of the rainbow scale
  var fadeStyle = 'fadeStyle' in oArg? oArg.fadeStyle : "RGB";      //Fade Style: "RGB", "HSL", "RAINBOW"
  
  document.write("<font style='font-family: "+'"Courier New", "Courier", "mono";'+"	font-size: x-small;'>");
  var outColor
  for (var y=0; y<fadeParts; y++) {
    if (fadeStyle.toUpperCase() == "RAINBOW") {
      outColor = rainbowColor(fromCol, rainbowScale, y/fadeParts);
    } else if (fadeStyle.toUpperCase() == "HSL") {
      outColor = fadeColorHSL(fromCol, toCol, y/(fadeParts-1));
    } else {  // if (fadeStyle.toUpperCase() == "RGB") {
      outColor = fadeColor(fromCol, toCol, y/(fadeParts-1));
    }
    document.write('<font color="' + outColor + '">' + outColor + '</font> ');
  }
  document.write('</font><br>');

}


//-->