var Server = "http://glidingforecast.on.net/";
var d2times = ["0800", "0900", "1000", "1100", "1200", "1300", "1400", "1500", "1600", "1700", "1800", "1900"];

/**********************/
/* Build the Day Menu */
/**********************/

var archiveMode = 0;

var Now = new Date().getTime(); // Time now - in milliSec(!)
var mS_Day = 24 * 60 * 60 * 1000;       // mS in a day
var T = new Date();                     // Instantiate a Date object
var dayName   = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var monthName = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

var day = document.forms[0].Day;        // save typing
var oldDate;

T.setTime(Now - mS_Day);                   // Yesterday
day.options[0] = new Option(dayName[T.getDay()] + ' ' + T.getDate() + ' ' + monthName[T.getMonth()] + " - Yesterday", "-1");
T.setTime(Now);                   // Today
day.options[1] = new Option(dayName[T.getDay()] + ' ' + T.getDate() + ' ' + monthName[T.getMonth()] + " - Today", "0");
T.setTime(Now + mS_Day);          // Tomorrow
day.options[2] = new Option(dayName[T.getDay()] + ' ' + T.getDate() + ' ' + monthName[T.getMonth()] + " - Tomorrow", "1");
T.setTime(Now + 2*mS_Day);        // Day after Tomorrow
day.options[3] = new Option(dayName[T.getDay()] + ' ' + T.getDate() + ' ' + monthName[T.getMonth()] + " - Day+2", "2");

oldDate = T.getDate();

/***********************/
/* Set Default Options */
/***********************/

var ref = document.forms[0];    // shorthand

// Install Time options
var times = d2times;
for (var i = 0; i < times.length; i++) {
  ref.Time.options[i] = new Option(times[i], times[i]);
 }

ref.Location.options[0] = new Option("VIC","VIC");
ref.Location.options[1] = new Option("NSW","NSW");
ref.Location.options[2] = new Option("QLD","QLD");
ref.Location.options[3] = new Option("TAS","TAS");
ref.Location.options[4] = new Option("SA","SA");
ref.Location.options[5] = new Option("WA","WA");
ref.Location.options[6] = new Option("NT","NT");

ref.Location.options[0].selected   = true;  // VIC
ref.Time.options[1].selected   = true;  // 0900
ref.Day.options[1].selected    = true;  // Today
ref.Param.options[1].selected  = true;  // wstar_bsratio

ref.paramdescr.value = "A composite plot displaying the Thermal Updraft Velocity contours in colors overlaid by a stipple representing the Buoyancy/Shear Ratio.  The stipple is heavy for B/S Ratios 0-4 and light for B/S Ratios 4-7.  The intent is to mark regions where a small B/S Ratio will make thermals difficult (or impossible) to work, though that depends upon pilot skill and circling radius";

var oldParam = ref.Param.options.value;
var oldDay = ref.Day.value;
var Loaded = new Array();
var Pics = new Array();
for (i = 0; i < ref.Time.options.length; i++){
  Pics[i] = new Image();
  Loaded[i] = false;
 }

whichBrowser(); // set browser


loadImage(1);   // Assume forwards

/********************* Material below adapted from *************************************
 * Cool DHTML tooltip script II- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
 * This notice MUST stay intact for legal use
 * Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
 ****************************************************************************************/

var offsetfromcursorX=1;        //Customize x offset of tooltip
var offsetfromcursorY=1;        //Customize y offset of tooltip
var offsetdivfrompointerX=00;   //Customize x offset of tooltip DIV
			        // relative to pointer image
var offsetdivfrompointerY=14;   //Customize y offset of tooltip DIV
			        // relative to pointer image. Tip: Set
			        // it to (height_of_pointer_image-1).

document.write('<div id="dhtmltooltip" onload="ddrivetip(\'Ctl-Click for value\')" ></div>'); //write out tooltip DIV
document.write('<img id="dhtmlpointer" src="arrow2.gif" >'); //write out pointer image

var enabletip=false;
if (ie) {
  var tipobj	 = document.all["dhtmltooltip"];
  var pointerobj = document.all["dhtmlpointer"];
} else {
  var tipobj	 = document.getElementById("dhtmltooltip") ;
  var pointerobj = document.getElementById("dhtmlpointer") ;
}

unfreezetip("Ctl-Click for a value");

document.getElementById("imgBox").onmousedown    = click;	// don't use onmouseup - doesn't always work!
document.getElementById("imgBox").onmousemove  = positiontip;
document.getElementById("selectors").onmouseover	= obscuretip;
document.getElementById("selectors").onmouseout	= unhidetip;
pointerobj.onmouseover = positiontip;

// JMW disable for now...
if (1) {
  hidetip();
  removePopup();
}


/*************** functions *****************************************************************/

function ietruebody() {
  return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body;
}


function ddrivetip(thetext, thewidth, thecolor){
  if (typeof thewidth != "undefined")
    tipobj.style.width = thewidth+"px";
  if (typeof thecolor != "undefined" && thecolor != "")
    tipobj.style.backgroundColor = thecolor;
  tipobj.innerHTML = thetext;
  enabletip = true;
  return false;
}

function positiontip(e)
{
  if (1) { // JMW disable for now 
    return;
  }

  if (enabletip){
    var nondefaultpos=false
      var curX=(ns) ? e.pageX : event.clientX+ietruebody().scrollLeft;
    var curY=(ns) ? e.pageY : event.clientY+ietruebody().scrollTop;

    //Find out how close the mouse is to the corner of the window
    var winwidth  = ie && !window.opera ? ietruebody().clientWidth : window.innerWidth-20;
    var winheight = ie && !window.opera ? ietruebody().clientHeight : window.innerHeight-20;

    var rightedge = ie &&!window.opera ? winwidth  - event.clientX - offsetfromcursorX : winwidth - e.clientX - offsetfromcursorX;
    var bottomedge= ie &&!window.opera ? winheight - event.clientY - offsetfromcursorY : winheight - e.clientY - offsetfromcursorY;

    var leftedge=(offsetfromcursorX<0) ? offsetfromcursorX*(-1) : -1000;

    //if the horizontal distance isn't enough to accomodate the width of the context menu
    if (rightedge < tipobj.offsetWidth){
      //move the horizontal position of the menu to the left by it's width
      tipobj.style.left = curX - tipobj.offsetWidth + "px";
      nondefaultpos = true;
    } else if (curX < leftedge) {
      tipobj.style.left = "5px";
    } else {
      //position the horizontal position of the menu where the mouse is positioned
      tipobj.style.left = curX + offsetfromcursorX - offsetdivfrompointerX + "px";
      pointerobj.style.left = curX + offsetfromcursorX + "px";
    }

    //same concept with the vertical position
    if (bottomedge<tipobj.offsetHeight){
      tipobj.style.top = curY - tipobj.offsetHeight - offsetfromcursorY + "px";
      nondefaultpos = true;
    } else{
      tipobj.style.top = curY + offsetfromcursorY + offsetdivfrompointerY + "px";
      pointerobj.style.top = curY + offsetfromcursorY + "px";
    }

    tipobj.style.visibility = "visible";
    if (!nondefaultpos) {
      pointerobj.style.visibility = "visible";
    }
  }
}

function removePopup()
{
  // Remove popup window
  try {
    if(paramWindow != "" ){
      paramWindow.close();
      paramWindow = "" ;
    }
  }
  catch(err) {
    ; // error irrlevant
  }
}

var tipstate = "";
function obscuretip()
{
  if(tipstate != "frozen")
    hidetip();
}


function unfreezetip(Str)
{
  if (1) { // JMW disable for now 
    return;
  }

  removePopup();
  unhidetip();
  tipobj.innerHTML = Str;
  tipobj.onmouseover  = positiontip;
  pointerobj.onmouseover  = positiontip;
  document.getElementById("imgBox").onmousemove = positiontip;
  tipstate = "";
}


function freezetip(){
  document.getElementById("imgBox").onmousemove = "";
  // document.getElementById("imgBox").onmouseout = "";
  pointerobj.onmouseover = "";
  tipobj.onmouseover = "";
  tipstate = "frozen";
}


function unhidetip()
{
  enabletip=true;
  tipobj.style.visibility="visible";
  pointerobj.style.visibility="visible";
}

function hidetip(){
  enabletip=false;
  tipobj.style.visibility="hidden";
  pointerobj.style.visibility="hidden";
}



/*****************************/
/* Get image click Coords    */
/*****************************/ 
function getPageCoords (element)
{
  var coords = {x : 0, y : 0};
  while (element) {
    coords.x += element.offsetLeft;
    coords.y += element.offsetTop;
    element = element.offsetParent;
  }
  return coords;
}


/*****************************/
/* Get image click Posn info */
/*****************************/ 
function getOffsets(evt)
{
  if( ie ) {		// Internet Exploder
    target = event.srcElement;
    if (typeof target.offsetLeft == 'undefined') {
      target = target.parentNode;
    }
    var pageCoords = getPageCoords(target);
    var eventCoords = {
      x: window.pageXOffset + event.clientX,
      y: window.pageYOffset + event.clientY
    }
  }
  else {		// NS etc
    var target = evt.target;
    if (typeof target.offsetLeft == 'undefined') {
      target = target.parentNode;
    }
    var pageCoords =getPageCoords(target);
    var	eventCoords = {
      x: window.pageXOffset + evt.clientX,
      y: window.pageYOffset + evt.clientY
    };

  }
  var offsets = {
    offsetX: eventCoords.x - pageCoords.x,
    offsetY: eventCoords.y - pageCoords.y
  }
  return offsets;
}

/********************************/
/* CallBack for onclick (image) */
/********************************/
function click(E)
{
  var buttn;
  var dirn = 1; // forwards

  // Catch a stupid selection
  if (ref.Param.value === "nope1") {
    return false;
  }

  /*	buttn	IE		NS (etc?)
   *  L			1			1
   *  M			4			2
   *  R			2			3
   */
  var LEFT 	= 1;
  var MID  	= 2;
  var RIGHT	= 3;
  if ( ie ) {
    shiftPressed	= event.shiftKey;
    ctrlPressed		= event.ctrlKey;
    altPressed		= event.altKey;
    switch(event.button){
    case 1:	buttn = LEFT;    break;
    case 2:     buttn = RIGHT;   break;
    case 3:	buttn = MID; 	 break;
    case 4:	buttn = MID;	 break;
    default:
      alert("I don't understand which butoon you pressed!\nButton # = " + event.button);
      break;
    }
  }
  else if (ns || ko || op ) {
    shiftPressed	= E.shiftKey;
    ctrlPressed		= E.ctrlKey;
    altPressed		= E.altKey;
    switch(E.which){
    case 1:	buttn = LEFT; 	break;
    case 2:	buttn = MID;	break;
    case 3:     buttn = RIGHT;	break;
    default:	alert("Which button was that?\nE.which = " + E.which); break;
    }				
  }
  else {
    alert("Which Button?\nE.which = " + E.which);
  }
			
  times = d2times;

  switch (buttn) {
  case 1:
    /**** ORDINARY CLICK -> NEXT TIME IN DAY ****/
    if(!shiftPressed && !ctrlPressed) {
      var i = ref.Time.selectedIndex;
      i = (i + 1) % times.length;
      ref.Time.options[i].selected   = true;
      unfreezetip("Ctl-Click for Value");
      break;
    }

    /**** CTRL-SHIFT -> PREVIOUS TIME IN DAY ****/
    else if(shiftPressed && ctrlPressed) {
      var i = ref.Time.selectedIndex;
      if (--i < 0) {
	i = (times.length - 1);
      }
      ref.Time.options[i].selected = true;
      dirn = -1; // backwards;
      unfreezetip("Ctl-Click for Value");
      break;
    }

    /**** SHIFT -> PARAMETER VALUE IN POPUP ****/
    else if (shiftPressed && !ctrlPressed){
      if( ie) {		//Internet Exploder
	wx  = event.offsetX;
	wy  = event.offsetY;
	ht  = window.theMap.height;
	wid = window.theMap.width;
      } else {		// NS etc
	var offsets = getOffsets(E);
	target = E.target;
	ht  = E.target.height;
	wid = E.target.width;
	wx  = offsets.offsetX;
	wy  = offsets.offsetY;
      }

      removePopup();

      parameter = checkParam();

      if(parameter === "") {
	unfreezetip("Unimplemented");
      } else { // Good parameter						
	unfreezetip("Getting Value ...");
	positiontip(E);
	blipSpotUrl = Server + "cgi-bin/get_rasp_blipspot.cgi";
	str = (archiveMode ? "UK%2b0" : ref.Day.value) // %2b == '+'
	  tail = "region=" + str
	  + "&grid="   + "d2"
	  + "&day=" + (archiveMode ? (ref.archiveYear.value + ref.archiveMonth.value + ref.archiveDay.value) : "0")
	  + "&i="      + wx + "&k=" + wy
	  + "&width="  + wid + "&height=" + ht
	  + "&linfo="	 +  1
	  + "&param="	 + parameter
	  ;
	txtPlace = "popUp";
	// alert("URL = " + blipSpotUrl + "\ntail = " + tail);
	doCallback(blipSpotUrl, tail);
	freezetip();
	tipobj.innerHTML = "See PopUp" ;
	removePopup();
      }
      break;
    }

    /* CONTROL -> PARAMETER VALUE IN TOOLTIP ****/
    else if(!shiftPressed && ctrlPressed){
      if( ie){		//Internet Exploder
	wx  = event.offsetX;
	wy  = event.offsetY;
	ht  = window.theMap.height;
	wid = window.theMap.width;
      }
      else{		// NS etc
	var offsets = getOffsets(E);
	target = E.target;
	ht  = E.target.height;
	wid = E.target.width;
	wx  = offsets.offsetX;
	wy  = offsets.offsetY;
      }

      removePopup();

      // if(archiveMode ) {
      // return false;	// Param Value not implemented for archiveMode
      // }

      parameter = checkParam();

      if(parameter === "") {
	unfreezetip("Unimplemented");
      }

      else { // Good parameter
	unfreezetip("Getting Value ...");
	positiontip(E);
	blipSpotUrl = Server + "cgi-bin/get_rasp_blipspot.cgi";
	str = (archiveMode ? "UK%2b0" : ref.Day.value) // %2b == '+'
	  tail = "region=" + str
	  + "&grid="   + "d2"
	  + "&day=" + (archiveMode ? (ref.archiveYear.value + ref.archiveMonth.value + ref.archiveDay.value) : "0")
	  + "&i="      + wx + "&k=" + wy
	  + "&width="  + wid + "&height=" + ht
	  + "&linfo="	 + 0
	  + "&time="	 + ref.Time.value + "lst"
	  + "&param="	 + parameter 
	  ;
	txtPlace = "tip";
	// alert("URL = " + blipSpotUrl + "\ntail = " + tail);
	doCallback(blipSpotUrl, tail);
	freezetip();
	tipobj.innerHTML = "Getting value ..." ;
	removePopup();
      }
      break;

    }

    case 3: // RIGHT - Next parameter
      var iParam = ref.Param.selectedIndex;
      iParam = ++iParam % ref.Param.options.length;
      if (ref.Param.options[iParam].value === "nope1"){
	iParam++;
      }
      ref.Param.options[iParam].selected = true;
      for (i = 0; i < times.length; i++){
	Loaded[i] = false;
      }
      break;
			
    /* NOT NEEDED
       case 2:	// MID - was Previous time in day
       alert("Use Ctrl-Shift-LeftClick for Previous Time in Day");
       break;
    */
  }

  loadImage(dirn);

  return false;		// Defeat normal contextmenu for Firefox
}

var txtPlace = "tip";

function writePopup()
{
  if (1) { // JMW disable for now 
    return;
  }

  // paramWindow = window.open('', "BLIPspot", "width=1200,height=200,toolbar=no,location=no,status=no,titlebar=no,resizable=yes" );
  paramWindow = window.open('', "_blank", "resizable=yes,height=200,titlebar=no,scrollbars=yes" );
  paramWindow.focus();
  paramWindow.document.write("<html><head></head><body><pre>" + req.responseText + "</pre></body></html>");
}


/********************************/
/* Set Image Size and Callbacks */
/********************************/
function setSize()
{
  var Ht;

  if (ns || ko) {
    Ht = window.innerHeight;
  }
  else if (ie) {
    Ht = document.body.offsetHeight;
  }
  else {
    Ht = 600;
  }

  tblHt = document.getElementById("selectors").offsetHeight;
  offset = document.getElementById("imgBox").offsetTop;
  if(tblHt < Ht){
    Ht = Ht - (2 * offset) ;  // Reduce Ht to allow for Offset, Padding, etc in browser
  }
  document.images[0].height = Ht;
  document.images[0].width  = Ht;
}


/****************************************************/
/* CallBack from the forms */
/****************************************************/
function doChange()
{
  var oldTime;


  /*Force 12Km if silly Grid value or a sounding
    if(ref.Param.value.match("sounding")) {
    ref.Grid.options[1].selected   = true;
    }

    /* If Grid, Param or Day changes:
    * Update Time options and reposition selector
    * Save current values, so can detect change
    * Load images
    */

  if((oldParam !== ref.Param.value) || (oldDay !== ref.Day.value) || (oldLocation != ref.Location.value)){
    for(i = 0; i < ref.Time.options.length; i++){
      Loaded[i] = false;
    }
  }

  if(ref.Param.value === "nope1" ) {
    return 0;               // Catch a stupid selection
  }

  // This might be a good place to load the parmater description?
  switch(ref.Param.value)
    {
    case "nope1":
      ref.paramdescr.value = "";
      break;
    case "wstar_bsratio":
      ref.paramdescr.value = "A composite plot displaying the Thermal Updraft Velocity contours in colors overlaid by a stipple representing the Buoyancy/Shear Ratio.  The stipple is heavy for B/S Ratios 0-4 and light for B/S Ratios 4-7.  The intent is to mark regions where a small B/S Ratio will make thermals difficult (or impossible) to work, though that depends upon pilot skill and circling radius";
      break;
    case "wstar":
      ref.paramdescr.value = "Average dry thermal updraft strength near mid-BL height.  Subtract glider descent rate to get average vario reading for cloudless thermals.  Updraft strengths will be stronger than this forecast if convective clouds are present, since cloud condensation adds buoyancy aloft (i.e. this negects cloudsuck).  W* depends upon both the surface heating and the BL depth";
      break;
    case "hwcrit":
      ref.paramdescr.value = "This parameter estimates the height at which the average dry updraft strength drops below 225 fpm and is expected to give better quantitative numbers for the maximum cloudless thermalling height than the BL Top height given above, especially when mixing results from vertical wind shear rather than thermals.  (Note: the present assumptions tend to underpredict the max. thermalling height for dry consitions.) In the presence of clouds the maximum thermalling height may instead be limited by the cloud base. Being for dry thermals, this parameter omits the effect of cloudsuck";
      break;
    case "dwcrit":
      ref.paramdescr.value = "No description given for this parameter: please visit http://www.drjack.info/RASP/INFO/parameters.html for more information";
      break;
    case "hbl":
      ref.paramdescr.value = "Height of the top of the mixing layer, which for thermal convection is the average top of a dry thermal.  Over flat terrain, maximum thermalling heights will be lower due to the glider descent rate and other factors.  In the presence of clouds (which release additional buoyancy aloft, creating cloudsuck) the updraft top will be above this forecast, but the maximum thermalling height will then be limited by the cloud base. Further, when the mixing results from shear turbulence rather than thermal mixing this parameter is not useful for glider flying.  NB: this BL Top is not the height where the Thermal Index (TI) is zero, which is a criteria used by many simple determinations of the BL top - instead, the RASP BL Top uses a more sophisticated BL Top criteria based on turbulent fluxes";
      break;
    case "dbl":
      ref.paramdescr.value = "Depth of the layer mixed by thermals or (vertical) wind shear.  This parameter can be useful in determining which flight direction allows better thermalling conditions when average surface elevations vary greatly in differing directions.  (But the same cautions mentioned under Height of BL Top also apply.)  It is also an important determinant of thermals strength (as is the Surface Heating)";
      break;
    case "bltopvariab":
      ref.paramdescr.value = "No description given for this parameter: please visit http://www.drjack.info/RASP/INFO/parameters.html for more information";
      break;
    case "sfcshf":
      ref.paramdescr.value = "Heat transferred into the atmosphere due to solar heating of the ground, creating thermals.  This parameter is an important determinant of thermals strength (as is the BL depth).  This parameter is obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "sfcsunpct":
      ref.paramdescr.value = "The solar radiation reaching the surface.  A fraction of this radiation goes into heating the air (see the Surface Heating parameter, to which this parameter can be compared).  This parameter is obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "sfctemp":
      ref.paramdescr.value = "The temperature at a height of 2m above ground level.  This can be compared to observed surface temperatures as an indication of model simulation accuracy; e.g. if observed surface temperatures are significantly below those forecast, then soaring conditions will be poorer than forecast.  This parameter is obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "sfcdewpt":
      ref.paramdescr.value = "The dew point temperature at a height of 2m above ground level.  This can be compared to observed surface dew point temperatures as an indication of model simulation accuracy; e.g. if observed surface dew point temperatures are significantly below those forecast, then BL cloud formation will be poorer than forecast.  This parameter is obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "nope1":
      ref.paramdescr.value = "";
      break;
    case "sfcwind":
      ref.paramdescr.value = "The speed and direction of the wind at 10m above the ground.  Speed is depicted by different colors and direction by streamlines.  This parameter is obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "blwind":
      ref.paramdescr.value = "The speed and direction of the vector-averaged wind in the BL.  This prediction can be misleading if there is a large change in wind direction through the BL (for a complex wind profile, any single number is not an adequate descriptor!)";
      break;
    case "bltopwind":
      ref.paramdescr.value = "The speed and direction of the wind at the top of the BL.  Speed is depicted by different colors and direction by streamlines";
      break;
    case "blwindshear":
      ref.paramdescr.value = "The vertical change in wind through the BL, specifically the magnitude of the vector wind difference between the top and bottom of the BL.  Note that this represents vertical wind shear and does not indicate so-called shear lines (which are horizontal changes of wind speed/direction)";
      break;
    case "wblmaxmin":
      ref.paramdescr.value = "Maximum grid-area-averaged extensive upward or downward motion within the BL as created by horizontal wind convergence.  Positive convergence is associated with local small-scale convergence lines (often called shear lines by pilots, which are horizontal changes of wind speed/direction) - however, the actual size of such features is much smaller than can be resolved by the model so only stronger ones will be forecast and their predictions are subject to much error.  If CAPE is also large, thunderstorms can be triggered.  Negative convergence (divergence) produces subsiding vertical motion, creating low-level inversions which limit thermalling heights.  This parameter can be noisy, so users should be wary.  For a grid resolution of 12km or better convergence lines created by terrain are commonly predicted - sea-breeze predictions can also be found for strong cases, though they are best resolved by smaller-resolution grids";
      break;
    case "nope1":
      ref.paramdescr.value = "";
      break;
    case "zsfclcldif":
      ref.paramdescr.value = "This evaluates the potential for small, non-extensive puffy cloud formation in the BL, being the height difference between the surface-based LCL (see below) and the BL top.  Small cumulus clouds are (simply) predicted when the parameter positive, but it is quite possible that the threshold value is actually greater than zero for your location so empirical evaluation is advised.  Clouds can also occur with negative values if the air is lifted up the indicated vertical distance by flow up a small-scale ridge not resolved by the model's smoothed topography";
      break;
    case "zsfclcl":
      ref.paramdescr.value = "This height estimates the cloudbase for small, non-extensive puffy clouds in the BL, if such exist i.e. if the Cumulus Potential parameter (above) is positive or greater than the threshold Cumulus Potential empirically determined for your site.  The surface LCL (Lifting Condensation Level) is the level to which humid air must ascend before it cools enough to reach a dew point temperature based on the surface mixing ratio and is therefore relevant only to small clouds - unlike the below BL-based CL which uses a BL-averaged humidity.  However, this parameter has a theoretical difficulty and quite possibly that the actual cloudbase will be higher than given here - so perhaps this should be considered a minimum possible cloudbase";
      break;
    case "zsfclclmask":
      ref.paramdescr.value = "Combining the previous two parameters, this depicts the Cumulus Cloudbase only at locations where the Cumulus Potential parameter is positive.  This single plot can be used, instead of needing to look at both the Cumulus Potential and Cumulus Cloudbase plots, if the threshold Cumulus Potential empirically determined for your site approximately equals the theoretical value of zero.  For locations where the actual threshold is greater than zero, as is often the case, this depiction will over-estimate the extent of the cumulus region";
      break;
    case "zblcldif":
      ref.paramdescr.value = "This evaluates the potential for extensive cloud formation (OvercastDevelopment) at the BL top, being the height difference between the BL CL (see below) and the BL top.  Extensive clouds and likely OD are predicted when the parameter is positive, with OD being increasingly more likely with higher positive values.  OD can also occur with negative values if the air is lifted up the indicated vertical distance by flow up a small-scale ridge not resolved by the model's smoothed topography.  [This parameter is truncated at -10,000 for plotting.]";
      break;
    case "zblcl":
      ref.paramdescr.value = "This height estimates the cloudbase for extensive BL clouds (OvercastDevelopment), if such exist, i.e. if the OvercastDevelopment Potential parameter (above) is positive.  The BL CL (Condensation Level) is based upon the humidity averaged through the BL and is therefore relevant only to extensive clouds (OvercastDevelopment) - unlike the above surface-based LCL which uses a surface humidity.  [This parameter is truncated at 22,000 for plotting.] ";
      break;
    case "zblclmask":
      ref.paramdescr.value = "Combining the previous two parameters, this depicts the OvercastDevelopment (OD) Cloudbase only at locations where the OD Potential parameter is positive.  This single plot can be used, instead of needing to look at both the OD Potential and OD Cloudbase plots, if the threshold OD Potential empirically determined for your site approximately equals the theoretical value of zero";
      break;
    case "blcwbase":
      ref.paramdescr.value = "This parameter is primarily for DrJack's use.  It predicts the cloud base of extensive clouds based on model-predicted formation of cloud water, giving the lowest height at which the predicted cloud water density is above a criterion value within the BL.  In theory it should be useful predicting OvercastDevelopment (OD) within the BL since it predicts extensive cloudiness, i.e. when BL clouds are predicted to extend over a full model gridcell volume.  However, the criterion to be used to indicate the presence of clouds is problematical since no single value reliably differentiates between mist and cloud concentrations.  This parameter has not yet been verified again actual conditions - comparision to flight observations will be needed to evaluate its usefulness";
      break;
    case "blcloudpct":
      ref.paramdescr.value = "This parameter provides an additional means of evaluating the formation of clouds within the BL and might be used either in conjunction with or instead of the other cloud prediction parameters.  It assumes a very simple relationship between cloud cover percentage and the maximum relative humidity within the BL.  The cloud base height is not predicted, but is expected to be below the BL Top height.  DrJack does not have a lot of faith in this prediction, since the formula used is so simple, and expects its predictions to be very approximate - but other meteorologists have used it and it is better than nothing.  Note: Since The the BL Cloud Cover, Cumulus Potential, and BL Extensive CloudBase are based upon fundamentally different model predictions -- respectively the predicted maximum moisture in the BL, the predicted surface moisture, and an explicit cloud-water prediction -- they can yield somewhat differing predictions, e.g. the Cumulus Potential can predict puffy cloud formation when the BL Cloud Cover is zero or vice versa.";
      break;
    case "cape":
      ref.paramdescr.value = "Convective Available Potential Energy indicates the atmospheric stability affecting deep convective cloud formation above the BL.  A higher value indicates greater potential instability, larger updraft velocities within deep convective clouds, and greater potential for thunderstorm development (since a trigger is needed to release that potential).  Note that thunderstorms may develop in regions of high CAPE and then get transported downwind to regions of lower CAPE.  Also, locations where both convergence and CAPE values are high can be subject to explosive thunderstorm development";
      break;
    case "rain3":
      ref.paramdescr.value = "Rainfall accumulated over past 3 hours.";
      break;
    case "nope1":
      ref.paramdescr.value = "";
      break;
    case "press850":
      ref.paramdescr.value = "Vertical velocity at a constant pressure level, plus wind speed/direction barbs.  [850/700/500mb presure levels are approximately at 5000/8000/19000 ftMSL or 1500/2500/5800 mMSL.]  Such upward motions can result from mountain wave or BL convergence.  A white dashed straight-line represents the location of the slice used for the [Vertical Velocity Slice through Vertical Velocity Maximum] parameter since these parameters are intended to be used in conjunction.  These parameters are obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "press700":
      ref.paramdescr.value = "Vertical velocity at a constant pressure level, plus wind speed/direction barbs.  [850/700/500mb presure levels are approximately at 5000/8000/19000 ftMSL or 1500/2500/5800 mMSL.]  Such upward motions can result from mountain wave or BL convergence.  A white dashed straight-line represents the location of the slice used for the [Vertical Velocity Slice through Vertical Velocity Maximum] parameter since these parameters are intended to be used in conjunction.  These parameters are obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "press500":
      ref.paramdescr.value = "Vertical velocity at a constant pressure level, plus wind speed/direction barbs.  [850/700/500mb presure levels are approximately at 5000/8000/19000 ftMSL or 1500/2500/5800 mMSL.]  Such upward motions can result from mountain wave or BL convergence.  A white dashed straight-line represents the location of the slice used for the [Vertical Velocity Slice through Vertical Velocity Maximum] parameter since these parameters are intended to be used in conjunction.  These parameters are obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "boxwmax":
      ref.paramdescr.value = "A vertical slice depicting vertical velocity (colors) and potential temperature (lines), intended to help analyze occurrences of strong upward motion.  The slice is taken through the location of the maximum vertical velocity found at a height of approximately 5000 ftAGL over a domain which excludes the outer edge of the domain (the value of that maximum and its location is given in a subtitle of the plot).  The slice parallells the wind direction at that height and is depicted by a white dashed line on the [Vertical Velocity at 850/700/500mb] paramter plots (with left-right on the slice always being left-right on the plan view).  Mt. wave predictions are best made using resultions no larger than 4km, since a coarser grid generally does not resolve the waves accurately.  Mountain waves tend to occur above the surface and tilt upwind with height, whereas BL convergences are surface-based and vertically oriented.  These parameters are obtained directly from WRF model output and not from a BLIPMAP computation";
      break;
    case "nope1":
      ref.paramdescr.value = "";
      break;
    }

  oldParam = ref.Param.value;
  oldDay = ref.Day.value;
  oldLocation = ref.Location.value;

  loadImage(1); // forwards

}

/************************************/
/* Load the Image, and the next one */
/************************************/
function loadImage(dirn)
{
  // Load image and next, depending on direction
  // -1 => backwards
  //  0 => neither
  //  1 => forwards
  if (T.getDate() != oldDate) {
    document.location.reload(true);
  }

  var tIdx = ref.Time.selectedIndex;
  var tValue;
  var     imgURL;

  for( i = 0; i < 2; i++){
    if (Loaded[tIdx]) {
      tIdx = (tIdx + dirn) % times.length;
      if (tIdx < 0)
	tIdx = times.length - 1;
      continue;
    }
    tValue = ref.Time.options[tIdx].value;
    var DayOffset="";
    if (ref.Day.value == "0") {
      DayOffset = "";
    }
    if (ref.Day.value == "1") {
      DayOffset = "+1";
    }
    if (ref.Day.value == "2") {
      DayOffset = "+2";
    }
    if (ref.Day.value == "-1") {
      DayOffset = "-1";
    }
    if ((ref.Location.value == "NT") || (ref.Location.value == "SA")) {
      tValue = tValue*1-70;
      if (tValue*1<1000) {
	tValue = "0"+tValue;
      }
    } 
    imgURL =  Server + "RASP/" 
      + ref.Location.value + DayOffset + "/FCST/"
      + ref.Param.value + ".curr" + DayOffset +"."
      + tValue + "lst."
      + "d2"
      + ".png"
      ;
    Pics[tIdx].src = imgURL;
    Loaded[tIdx] = true;
    if (dirn === 0)
      break;

    tIdx = (tIdx + dirn) % times.length;
    if (tIdx < 0)
      tIdx = times.length - 1;
  }

  document.images[0].src = Pics[ref.Time.selectedIndex].src;

  // following added 20081231 to fill imagelink part of table
  document.getElementById('imagelink').innerHTML = 
    "<font face=verdana,arial,helvetica>Link to image <a href=" 
    + document.images[0].src + ">here</a></font>" ;

}

function badImage()
{
  document.images[0].src = "http://glidingforecast.on.net/RASP/error/RASP_NA.png";
}


/******************************************************
 * Check if param is implemented
 *
 * Returns true if not in list of unimplemented params
 ******************************************************/
function checkParam()
{
  var badParams = new Array();
  badParams[0]  = "";
  badParams[1]  = "press850";
  badParams[2]  = "press700";
  badParams[3]  = "press500";
  badParams[4]  = "boxwmax";
  badParams[5]  = "sounding1";
  badParams[6]  = "sounding2";
  badParams[7]  = "sounding3";
  badParams[8]  = "sounding4";
  badParams[9]  = "sounding5";
  badParams[10] = "sounding6";
  badParams[11] = "sounding7";
  badParams[12] = "sounding8";
  badParams[13] = "sounding9";
  badParams[14] = "sounding10";
  badParams[15] = "sounding11";
  badParams[16] = "sounding12";
  badParams[17] = "sounding13";
  badParams[18] = "sounding14";
  badParams[19] = "sounding15";
  badParams[20] = "topo" ;
  badParams[21] = "zblclmask" ;
  badParams[22] = "zsfclclmask" ;
  badParams[23]  = "press1000";
  badParams[24]  = "press950";

  for( i = 0; i < badParams.length; i++) 
    if( ref.Param.value === badParams[i])
      return "" ;

  var newParams = new Array();
  newParams[0]  = "wstar_bsratio";
  newParams[1] = "sfcwind" ;
  newParams[2] = "blwind" ;
  newParams[3] = "bltopwind" ;

  for( i = 0; i < newParams.length; i++) 
    if( ref.Param.value === newParams[i]){
      if(ref.Param.value === "wstar_bsratio")
	return("wstar bsratio");
      if(ref.Param.value === "sfcwind")
	return("sfcwindspd sfcwinddir");
      if(ref.Param.value === "blwind")
	return("blwindspd blwinddir");
      if(ref.Param.value === "bltopwind")
	return("bltopwindspd bltopwinddir");
    }

  return ref.Param.value ;
}


var req = false;
var responseText;

function doCallback(url, data)
{
  /************************************************/
  /* This stuff needed if running from file://...
     try {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
     } catch (e) {
     alert("Permission UniversalBrowserRead denied.");
     }
     // End This stuff needed
     ************************************************/

  if (window.XMLHttpRequest) {
    try {
      req = new XMLHttpRequest();
    }
    catch (e) {
      req = false;
    }
  }
  else if (window.ActiveXObject) {
    // For Internet Explorer on Windows
    try {
      req = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      try {
	req = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {
	req = false;
      }
    }
  }

  if (req) {
    req.onreadystatechange = processReqChange;
    try {
      req.open('POST', url, true);
    }
    catch (E){
      alert(E);
    }
    req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    req.send(data);
  }
  else  {
    document.println("Failed");
  }
}

function processReqChange()
{
  if (req.readyState == 4) { // only if req shows 'loaded'
    if (req.status == 200) { // only if 'OK'
      // alert("Response = \"" + req.responseText + "\"");
      if(txtPlace === "tip"){
	tipobj.innerHTML = req.responseText;
	// A rather horrible hack to identify 2-line responses
	if(tipobj.innerHTML.indexOf('\n') != tipobj.innerHTML.length - 2){
	  tipobj.innerHTML = tipobj.innerHTML.replace(/\n/, (ref.Param.value === "wstar_bsratio" ? " BS: ": " Dirn: ")); 
	}
	// alert("Tip text = " + tipobj.innerHTML);
      }
      else
	writePopup();
    }
    else {
      alert('There was a problem retrieving the XML data: ' + req.responseText);
    }
  }
}



/*********************************/
/* Return false for context Menu */
/*********************************/
function retFalse()
{
  return false;
}


/******************/
/* Which Browser? */
/******************/
var ns;
var ko;
var ie;

function whichBrowser()
{
  // alert("Browser = " + navigator.appName);
  ns = navigator.appName === 'Netscape' ;
  ie = navigator.appName === 'Microsoft Internet Explorer' ;
  ko = navigator.appName === 'Konqueror' ;
}
