// helper script for contrast ratio measurement
// Copyright 2007, Han-Kwang Nienhuys, lagom.nl

// global vars
warnings = "";
data_changed = 0;

function debugmsg(s) {
     elm = document.getElementById("debug");
     if (elm) {
	  elm.innerHTML = elm.innerHTML + s + "<br>";
     }
}

// resize imgs and divs to window size
function blocksize() {
    var blocklist = ["whiteblock", "blackblock"];
    var xres = getWindowWidth();
    var yres = getWindowHeight();
    for (i = 0; i < blocklist.length; ++i) {
        var elm = document.getElementById(blocklist[i]);
	if (elm) {
	     elm.style.width = (xres*0.94-4) + "px";
	     elm.style.height = (yres*0.94-4) + "px";
	}
    }
   var tdlist = document.getElementById("checker").getElementsByTagName("td");
   var tdwid = (xres*0.235-1) + "px";
   var tdhgt = (yres*0.313-1) + "px";
   for (i = 0; i < tdlist.length; ++i) {
	tdlist[i].style.width = tdwid;
	tdlist[i].style.height = tdhgt;
   }
   tdlist = document.getElementById("twoblocks").getElementsByTagName("td");
   var tdwid = (xres*0.47-2) + "px";
   var tdhgt = (yres*0.94-4) + "px";
   for (i = 0; i < tdlist.length; ++i) {
	tdlist[i].style.width = tdwid;
	tdlist[i].style.height = tdhgt;
   }
}

// resize images on window resize
window.onresize = blocksize;

// 1/500 -> 0.002
function convET(et) {
     etlist = et.split("/");
     if (etlist.length != 2)
	  return 1.0*et;
     else
	  return 1.0*etlist[0]/etlist[1];
}

// remove whitespace etc.
function getcleanvar(id) {
     v = document.getElementById(id).value;
     cleanv = v.replace(/[^0-9.\/]/, "");
     document.getElementById(id).value = cleanv;
     return convET(cleanv);
}

// return radio button status (getflag=1) 
// or set status (getflag = 0)
// wrapid is id of html tag that encloses the radio button set
function getset_radio(wrapid, value, getflag) {
     var radios = document.getElementById (wrapid);
     var inputs = radios.getElementsByTagName ('input');
     if (getflag) {
	  // get radio button status
	  for (i = 0; i < inputs.length; ++i) {
	       if (inputs[i].type == 'radio' && inputs[i].checked)
		    return inputs[i].value;
	  }
     } else {
	  // set
	  for (i = 0; i < inputs.length; ++i) {
	       if (inputs[i].type == 'radio' && inputs[i].value == value) {
		    inputs[i].checked = "checked";
		    return;
	       }
	  }
     }
}

// get relative luminance values 
// from histogram directly or from RGB
// return: hist=0/rgb=255 -> 1, hist=2.5,rgb=118 -> 0.18
function get_rellum(histid, rgbid) {
     var rgb_flag = (getset_radio('hrgb_radios', '', 1) == 'rgb');
     // calculate relative luminance according to selected method 
     var rellum = 0;
     if (rgb_flag) {
	  v = document.getElementById(rgbid).value;
	  // cleanup and split into r,g,b
	  v = v.replace(/ /, "");
	  newv = v.replace(/[^0-9,/]/, "");
	  if (newv != v)
	       warnings = warnings + "RGB values must be formatted like 123,234,123. ";
	  v = newv;
	  rgblist = v.split(",");
	  if (rgblist.length != 3) {
	       rgblist = [ 1, 1, 1 ];
	       warnings = warnings + "Error in RGB values; there should be three, separated by commas. ";
	  }
	  var changed = 0;
	  for (i = 0; i < 3; ++i) {
	       if (rgblist[i] > 255) {
		    rgblist[i] = 255; changed = 1;
	       } else if (rgblist[i] < 1) {
		    rgblist[i] = 1; changed = 1;
	       }
	  }
	  if (changed) {
	       warnings = warnings + "Error in RGB values; they should be between 1 and 255. ";
	  }
	  v = "" + rgblist[0] + "," + rgblist[1] + "," + rgblist[2];
	  // calculate relative luminance according to sRGB or Adobe RGB
	  k = (0.3*rgblist[0] + 0.6*rgblist[1] + 0.1*rgblist[2]) / 255;
	  if (k <= 0.196)
	       warnings = warnings + "Warning: low RGB values (below 50) are unreliable. ";
	  else if (k >= 0.86)
	       warnings = warnings + "Warning: high RGB values (above 220) are unreliable. ";

	  if (getset_radio('selectsrgb', '', 1) == 1) {
	       // sRGB
	       if (k > 0.04045) 
		    rellum = Math.pow(((k+0.055)/1.055),2.4);
	       else
		    rellum = k/12.92;
	  } else {
	       // Adobe RGB
	       var ga=2.19921875;
	       var r=rgblist[0], g=rgblist[1], b=rgblist[2];
	       rellum = 0.3*Math.pow(r, ga) + 0.6*Math.pow(g, ga) + 0.1*Math.pow(b, ga);
	  }
     } else {
	  hist = getcleanvar(histid);
	  if (hist >= 5)
	       warnings = warnings + "Warning: histogram values of 5 and larger are unreliable. ";
	  else if (hist <= 0.7)
	       warnings = warnings + "Warning: histogram values below 1 are unreliable. ";
	  rellum = Math.pow(0.5, hist);
     }
     return rellum;
}

// calculate c-ratio
function calcratio() {
     warnings = "";
     
     et0 = getcleanvar("et0");
     et1 = getcleanvar("et1");
     f0 = getcleanvar("f0");
     f1 = getcleanvar("f1");
     iso0 = getcleanvar("iso0");
     iso1 = getcleanvar("iso1");
     rellum0 = get_rellum("hist0", "rgb0");
     rellum1 = get_rellum("hist1", "rgb1");
     // warnings
     if (f0 != f1) 
	  warnings = warnings + "Warning: different F numbers may cause up to 15% error in the calculated contrast ratio. ";
     if (iso0 != iso1)
	  warnings = warnings + "Warning: different ISO numbers may cause errors in the calculated contrast ratio, " + 
	       "especially if one of the numbers is low (&lt;100) or high (&ge;800). ";
     if (et1 < 0.00199)
	  warnings = warnings + "Warning: shutter times shorter than 1/500 s may be inaccurate. Try increasing the EV compensation.";
     if (et0 > 1.01)
	  warnings = warnings + "Warning: shutter times longer than 1 s may cause noise problems. Try decreasing the EV compensation.";
	       
     
     // new calculation dd 20071127
     // L = 10 N^2 2^(-E) / 0.18 q t = 85.5 N^2 2^(-E) / ISO t
     // q = 0.65 for a typical lens (=0.83 * pi/4) (previous version assumed q=pi/4)
     // http://en.wikipedia.org/wiki/Film_speed
     var lum0 = 85.5*(f0*f0) / (et0 * iso0) * rellum0;
     var lum1 = 85.5*(f1*f1) / (et1 * iso1) * rellum1;
     var ratio = lum1/lum0;
     if (ratio < 15) 
	  ratio = ratio.toFixed(1);
     else
	  ratio = ratio.toFixed(0);
     
     document.getElementById("ratio").innerHTML = ratio + " : 1";
     document.getElementById("lum0").innerHTML = lum0.toFixed(2) + " cd/m<sup>2</sup>";
     document.getElementById("lum1").innerHTML = lum1.toFixed(0) + " cd/m<sup>2</sup>";
     
     // log some statistics
     var stat = "";
     if (data_changed) {
	  var smethod = (getset_radio('hrgb_radios', '', 1) == 'rgb') ? "rgb" : "hist";
	  stops0 = -Math.log(rellum0)/Math.log(2);
	  stops1 = -Math.log(rellum1)/Math.log(2);
	  et1inv = 1/et1;
	  stat = "cratio=" + ratio + ",tfih=" + et0.toFixed(1) + ",";
	  stat += f0.toFixed(1) + "," + iso0.toFixed(0) + "," ;
	  stat += stops0.toFixed(1) +";1/" + et1inv.toFixed(0) + ",";
	  stat += f1.toFixed(1) + "," + iso1.toFixed(0) + ",";
	  stat += stops1.toFixed(1) + ";" + smethod;
	  stat = 'stats?' + stat; // url
	  img_el = document.getElementById('statimg');
	  if (img_el) {
	      img_el.src = stat;
	  }
     }
     document.getElementById("warnings").innerHTML = warnings;
     return false;
}

function hrgb_update(is_rgb)
{
     var d = document;
     if (is_rgb) {
	  d.getElementById("rgb0").className = "";
	  d.getElementById("rgb1").className = "";
	  d.getElementById("hist0").className = "inactive";
	  d.getElementById("hist1").className = "inactive";
	  getset_radio("hrgb_radios", "rgb", 0);
     } else {
	  d.getElementById("rgb0").className = "inactive";
	  d.getElementById("rgb1").className = "inactive";
	  d.getElementById("hist0").className = "";
	  d.getElementById("hist1").className = "";
	  getset_radio("hrgb_radios", "hist", 0);
     }
     data_changed = 1;
     return true;
}

function resetform()
{
     document.forms.calcform.reset(); 
     document.getElementById("ratio").innerHTML = "??";
     document.getElementById("lum0").innerHTML = "??";
     document.getElementById("lum1").innerHTML = "??";
     hrgb_update(0);
}
