/******************************************************************************/
/*            This source code is part of the Mopra schedule maker            */
/******************************************************************************/
/* v 1.0 09-JUL-2009 Balt Indermuehle                                         */
/*          OCT      created                                                  */
/*       08 OCT 2010 modified to allow filename creation                      */
/******************************************************************************/
/******************************************************************************/
var canvas_width = 1220;
var canvas_height = 900;
var jg;

var freqs = new Array;
var sb1 = new Array;
var sb2 = new Array;
var sb3 = new Array;
var sb4 = new Array;
var CF;

/***************************************************************************************
***************************************************************************************/
function expand(){
  var c = document.getElementById("canvas");
  var x = document.getElementById("expander");
  
  var content = "How this works:<br/><ul>";
  content += "<li>Enter up to 20 line frequencies in MHz or select them from the list</li>";
  content += "<li>The program automatically tries to optimize which zoom windows to use giving preference to the window with the least distance of the line from the band centre.</li>";
  content += "<li>You can manually enter a different center frequency and click the Update button to reflect the changes</li>";
  content += "<li>You also can move the center frequency up and down by 10 MHz increments using the respective buttons</li>";
  content += "<li>If you're satisfied that the center frequency looks good, click the Save and Close button. The values for the zoom windows and the center frequency will automatically be transferred into the appropriate inputs.</li>";
  content += "</ul>";
  content += "<select name=\"selline\" id=\"selline\">";
  content += "<option value=84521.206>CH3OH"
  content += "<option value=86243.440>SiO"
  content += "<option value=86340.167>H13CN"
  content += "<option value=86754.330>H13CO+"
  content += "<option value=88631.8473>HCN"
  content += "<option value=89188.526>HCO+"
  content += "<option value=90663.572>HNC"
  content += "<option value=93173.480>N2H+"
  content += "<option value=97980.953>CS"
  content += "<option value=100076.385>HCCCN"  
  content += "<option value=109757.587>SO2"
  content += "<option value=109782.173>C18O"
  content += "<option value=110201.353>13CO"
  content += "<option value=112358.988>C17O"
  content += "<option value=115271.202>12CO";
  content += "</select> OR enter manual frequency: <input name=\"manfreq\" id=\"manfreq\" value=\"\" size=8> MHz<br/>"
  content += "<i>Optional:</i> Topocentric velocity correction to apply: <input name=\"velo\" id=\"velo\" value=\"0\" size=5> km/s (+ redshift, - blueshift)<br/>"
  content += "<i>Optional:</i> Line width to plot (km/s). Note that the zoom window optimization does not work when this is set! <input name=\"width\" id=\"width\" value=\"0\" size=5> km/s<br/>"
  content += "Press <input type=\"button\" VALUE=\"Add\" onClick=\"selfreq();\"> to add the velocity corrected frequencies, or simply enter the sky frequencies manually below:"
  content += "<table border=0><tr>";
  content += "<td>1: <input name=\"f1\" id=\"f1\" value=\"\" size=8> MHz<br/>2: <input name=\"f2\" id=\"f2\" value=\"\" size=8> MHz<br/>3: <input name=\"f3\" id=\"f3\" value=\"\" size=8> MHz<br/>4: <input name=\"f4\" id=\"f4\" value=\"\" size=8> MHz<br/> 5: <input name=\"f5\" id=\"f5\" value=\"\" size=8> MHz<br/></td>";
  content += "<td>&nbsp;6: <input name=\"f6\" id=\"f6\" value=\"\" size=8> MHz<br/>&nbsp;7: <input name=\"f7\" id=\"f7\" value=\"\" size=8> MHz<br/>&nbsp;8: <input name=\"f8\" id=\"f8\" value=\"\" size=8> MHz<br/>&nbsp;9: <input name=\"f9\" id=\"f9\" value=\"\" size=8> MHz<br/>10: <input name=\"f10\" id=\"f10\" value=\"\" size=8> MHz<br/></td>";
  content += "<td>11: <input name=\"f11\" id=\"f11\" value=\"\" size=8> MHz<br/>12: <input name=\"f12\" id=\"f12\" value=\"\" size=8> MHz<br/>13: <input name=\"f13\" id=\"f13\" value=\"\" size=8> MHz<br/>14: <input name=\"f14\" id=\"f14\" value=\"\" size=8> MHz<br/>15: <input name=\"f15\" id=\"f15\" value=\"\" size=8> MHz<br/></td>";
  content += "<td>16: <input name=\"f16\" id=\"f16\" value=\"\" size=8> MHz<br/>17: <input name=\"f17\" id=\"f17\" value=\"\" size=8> MHz<br/>18: <input name=\"f18\" id=\"f18\" value=\"\" size=8> MHz<br/>19: <input name=\"f19\" id=\"f19\" value=\"\" size=8> MHz<br/>20: <input name=\"f20\" id=\"f20\" value=\"\" size=8> MHz<br/></td>";
  content += "</tr></table><br/>";
  content += "Center Frequency: <input name=\"cf\" id=\"cf\" value=\"\" size=8> MHz <input type=\"button\" VALUE=\"Update\" onClick=\"updateCF();\"> <input type=\"button\" VALUE=\"+ 10 MHz\" onClick=\"add10();\"> <input type=\"button\" VALUE=\"- 10 MHz\" onClick=\"sub10();\"><br/>";
  content += "Band 1 Zooms: <input name=\"b1z\" id=\"b1z\" value=\"\" size=20><br/>";
  content += "Band 2 Zooms: <input name=\"b2z\" id=\"b2z\" value=\"\" size=20><br/>";
  content += "Band 3 Zooms: <input name=\"b3z\" id=\"b3z\" value=\"\" size=20><br/>";
  content += "Band 4 Zooms: <input name=\"b4z\" id=\"b4z\" value=\"\" size=20><br/>";
  content += "When satisfied with the zoom window numbers and center frequency, press <input type=\"button\" VALUE=\"Save and close\" onClick=\"saveandclose();\"><br/>"

  if ( c.style.width != "0px" ) {
    x.innerHTML = "Open";
    c.innerHTML = "";
    c.style.width = '0px';
    c.style.height = '0px';
  } else {
    x.innerHTML = "Close";
    c.style.width = canvas_width;
    c.style.height = canvas_height;
    c.style.padding = '10px';
    c.innerHTML = content;
    jg = new jsGraphics("canvas");
  }

  draw();
}

/***************************************************************************************
***************************************************************************************/
// shiftfreq
// shifts the inputted freqency by the km/s entered in the topo velo box
function shiftfreq(restfreq) {
  return restfreq*(1-(document.getElementById("velo").value/3e+5));
}

/***************************************************************************************
***************************************************************************************/
// selfreq
// select the currently selected line frequency from the dropdown list into
// the next available frequency text box

function selfreq() {
  var i = 0;  
  for (i = 1; i <= 20; i++ ) {
    if ( document.getElementById("f" + i).value == "" ) {
      if ( document.getElementById("manfreq").value == "" ) {
        document.getElementById("f" + i).value = shiftfreq(parseFloat(document.getElementById("selline").value));
      } else {
        document.getElementById("f" + i).value = shiftfreq(parseFloat(document.getElementById("manfreq").value));
      }
      break;
    }
    if ( i == 20 ) {
      alert("The maximum of 20 lines has been reached. This is a soft limitation, complain to Balt to increase the number of lines!");
      return;
    }
  }
  update();
}

/***************************************************************************************
***************************************************************************************/
// updateCF
// updates the screen with the manually entered center frequency
function updateCF() {
  CF = parseFloat(document.getElementById("cf").value);
  document.getElementById("cf").value = CF;
  update(CF);
}

/***************************************************************************************
***************************************************************************************/
// add10
// adds 10 MHz to the CF
function add10() {
  CF = parseFloat(document.getElementById("cf").value);
  CF += 10;
  document.getElementById("cf").value = CF;
  update(CF);
}

/***************************************************************************************
***************************************************************************************/
// sub10
// subtracts 10 MHz to the CF
function sub10() {
  CF = parseFloat(document.getElementById("cf").value);
  CF -= 10;
  document.getElementById("cf").value = CF;
  update(CF);
}

/***************************************************************************************
***************************************************************************************/
// update
// updates the screen and calculations

function update(thisCF) {

  var i = 0;
  var j = 0;
  
  var freqspan = 0;
  var fmax = 0;
  var fmin = 1000000;
  var lowerdelta = 0;
  var upperdelta = 0;
  
  // delete previous values from the zoom window definitions
  document.getElementById("b1z").value = "";
  document.getElementById("b2z").value = "";
  document.getElementById("b3z").value = "";
  document.getElementById("b4z").value = "";
  
  // delete all frequencies
  freqs.length = 0;
  
  for ( i=1; i<=20; i++ ) {
    if ( document.getElementById("f" + i).value != "" ) {
      freqs.push(parseFloat(document.getElementById("f" + i).value));
    }
  }
  
  for ( i=0; i<freqs.length; i++ ) {
    // find min and max
    fmax = Math.max(freqs[i], fmax);
    fmin = Math.min(freqs[i], fmin);
  }
  
  if ( fmax - fmin > 8280 ) {
    alert("Your highest and lowest frequencies are " + Math.round((fmax - fmin)/1000) + " GHz apart. They cannot be more than 8GHz apart and cannot fit into one observing run. Please remove the highest/lowest frequency from your list and try again.");
    return;
  }
  
  if ( thisCF == null ) {
    // first approximation: CF = (max - min) / 2 + min. Good enough to be within 1 MHz
    CF = Math.round(((fmax - fmin) / 2 + fmin));
    document.getElementById("cf").value = CF;
  } else {
    CF = thisCF;
  }
  
  // run through all frequencies and find the windows
  var band = "";
  var w1 = 0;
  var w2 = 0;
  var zcd1;   // zcd = zoom centre distance
  var zcd2;
  var bz;     // best zoom
  var b1zc = 0; // band 1 zoom count
  var b2zc = 0;
  var b3zc = 0;
  var b4zc = 0;
  
  for ( j=0; j<freqs.length; j++ ) {
    // find this frequencies two windows:
    var w1 = (freqs[j]-CF) / 69;
    w1 = Math.floor(w1); //lower window
    w2 = w1 + 1;
    
    // find the minimum zoom center distance in windows 1 and 2
    zcd1 = Math.abs( w1 * 69 + CF-freqs[j] );
    zcd2 = Math.abs( w2 * 69 + CF-freqs[j] );
    
    //debugprint("zcd1 " + w1 + ":" + Math.round(zcd1));
    //debugprint("zcd2 " + w2 + ":" + Math.round(zcd2));
    
    // the zoom window with the least zoom center distance
    if (zcd1 < zcd2) {
      bz = w1;
    } else {
      bz = w2;
    }
    
    if ( bz >= -59 && bz <= -30 ) {
      if ( document.getElementById("b1z").value.length > 0 ) {
        document.getElementById("b1z").value = document.getElementById("b1z").value + "," + bz;
      } else {
        document.getElementById("b1z").value = bz
      }
      b1zc++;
    }

    if ( bz >= -29 && bz <= 0 ) {
      if ( document.getElementById("b2z").value.length > 0 ) {
        document.getElementById("b2z").value = document.getElementById("b2z").value + "," + bz;
      } else {
        document.getElementById("b2z").value = bz
      }
      b2zc++;
    }

    if ( bz >= 1 && bz < 29 ) {
      if ( document.getElementById("b3z").value.length > 0 ) {
        document.getElementById("b3z").value = document.getElementById("b3z").value + "," + bz;
      } else {
        document.getElementById("b3z").value = bz
      }
      b3zc++;
    }

    if ( bz >= 30 && bz < 59 ) {
      if ( document.getElementById("b4z").value.length > 0 ) {
        document.getElementById("b4z").value = document.getElementById("b4z").value + "," + bz;
      } else {
        document.getElementById("b4z").value = bz
      }
      b4zc++;
    }

  }
  
  // sanity checks:
  if ( b1zc > 4 ) {
    alert("Band 1 contains more than 4 Zoom windows! This configuration will not work, please adjust it.");
  }
  
  if ( b2zc > 4 ) {
    alert("Band 2 contains more than 4 Zoom windows! This configuration will not work, please adjust it.");
  }
  
  if ( b3zc > 4 ) {
    alert("Band 3 contains more than 4 Zoom windows! This configuration will not work, please adjust it.");
  }
  
  if ( b4zc > 4 ) {
    alert("Band 4 contains more than 4 Zoom windows! This configuration will not work, please adjust it.");
  }
  
  // update the graphical display
  
  draw();
}

/***************************************************************************************
***************************************************************************************/
function debugprint(text) {
  document.getElementById("debuglog").innerHTML += "<br/>" + text;
}

/***************************************************************************************
***************************************************************************************/
// draw
// draws the graphical representation of the zoom window arrangements
function draw() {
  var top = 520;
  
  jg.setColor("#eeeeee");
  jg.fillRect(5,top, canvas_width-5, canvas_height-top);
  
  jg.setStroke(1);
  jg.setColor("#000000");
  jg.setFont("arial","12px", Font.BOLD);
  //jg.drawString("MOPS Zoom Windows", 10, top+10);
  jg.drawString("Center Frequency: " + CF + " MHz", canvas_width/2, top+10);
  
  jg.setFont("arial","9px");
  
    //draw the lines. Draw them first so they're below the windows
  jg.setColor("#0000ff");
  for ( j=0; j<freqs.length; j++ ) {
    //320 pixels = 2208 MHz
    var x = 10 + (( freqs[j] - (CF - 4140)) * ( 320 / 2208));
    jg.setStroke(Stroke.DOTTED);
    if ( document.getElementById("width").value != 0 ) {
      // line widths
      var lw = Math.abs(freqs[j] - freqs[j]*(1-(document.getElementById("width").value/3e+5)));
      jg.setStroke(1 * lw * (320 / 2208));
    }
    jg.drawLine(x,top+40,x,top+150);
    jg.drawString(j+1, x,top+160);
  }
  
  
  jg.setStroke(1);
  jg.setColor("#000000");
  
  // band 1
  jg.setColor("#000000");
  x = 10 + (-59+59)*10;
  jg.drawLine(x,top+30,x,top+50);
  x = 10 + (-27+59)*10;
  jg.drawLine(x,top+30,x,top+50);
  x = 10 + (-44+59)*10;
  jg.drawString("Band 1", x, top+30);
  
  for (i=-59; i<=-29; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+50, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+50, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+50, 20, "center");
  }

  for (i=-58; i<=-30; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+60, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+60, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+60, 20, "center");
  }
  
  // band 2  
  jg.setColor("#000000");
  x = 10 + (-29+59)*10;
  jg.drawLine(x,top+70,x,top+110);
  x = 10 + (3+59)*10;
  jg.drawLine(x,top+70,x,top+110);
  x = 10 + (-14+59)*10;
  jg.drawString("Band 2", x, top+100);
  
    for (i=-29; i<=1; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+70, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+70, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+70, 20, "center");
  }

  for (i=-28; i<=0; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+80, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+80, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+80, 20, "center");
  }
  
  // band 3
  jg.setColor("#000000");
  x = 10 + (-1+59)*10;
  jg.drawLine(x,top+30,x,top+50);
  x = 10 + (31+59)*10;
  jg.drawLine(x,top+30,x,top+50);
  x = 10 + (14+59)*10;
  jg.drawString("Band 3", x, top+30);

  for (i=-1; i<=29; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+50, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+50, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+50, 20, "center");
  }

  for (i=0; i<=28; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+60, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+60, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+60, 20, "center");
  }  
  
  // band 4
  jg.setColor("#000000");
  x = 10 + (29+59)*10;
  jg.drawLine(x,top+70,x,top+110);
  x = 10 + (61+59)*10;
  jg.drawLine(x,top+70,x,top+110);
  x = 10 + (44+59)*10;
  jg.drawString("Band 4", x, top+100);
  
  for (i=29; i<=59; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+70, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+70, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+70, 20, "center");
  }

  for (i=30; i<=58; i+=2) {
    //default colour:
    jg.setColor("#99ccff");
    for ( j=0; j<freqs.length; j++ ) {
      if ( (CF + i * 69) - 69 < freqs[j] && (CF + i * 69) + 69 > freqs[j] ) {
        jg.setColor("#ff0000");
      }
    }
    jg.fillRect(10 + (i+59)*10, top+80, 20, 10);
    jg.setColor("#000000");
    jg.drawRect(10 + (i+59)*10, top+80, 20, 10);
    jg.drawStringRect(""+i, 10 + (i+59)*10, top+80, 20, "center");
  }
  
  
  jg.paint();
}

/***************************************************************************************
***************************************************************************************/
// saveandclose
// saves and closes the graphical frequency editor

function saveandclose() {
  document.getElementById("ctrfreq").value = document.getElementById("cf").value
  document.getElementById("configz1").value = document.getElementById("b1z").value
  document.getElementById("configz2").value = document.getElementById("b2z").value
  document.getElementById("configz3").value = document.getElementById("b3z").value
  document.getElementById("configz4").value = document.getElementById("b4z").value
  expand();
}

/***************************************************************************************
***************************************************************************************/
// formatFilename
// formats the filename to make sure it contains no spaces and only valid filename characters
function formatFilename(thistext) {
  var newText = thistext.value.replace(/[^a-zA-Z0-9-.]/g,'_');
  // check if file ends in .sch, if not, add it.
  if ( newText.indexOf(".sch", newText.length - 5 ) == -1 ) { 
    newText += '.sch';
  }
  if ( thistext.value != newText ) {
    alert("The filename you supplied has invalid characters in it. They've been replaced, please check the filename still says what you want it to.");
    thistext.value = newText;
  }
  
}

/***************************************************************************************
***************************************************************************************/
// formatSourcename
// formats the source name to make sure it contains no spaces and only valid filename characters
function formatSourcename(thistext) {
  var newText = thistext.value.replace(/[^a-zA-Z0-9-.]/g,'_');

  if ( thistext.value != newText ) {
    alert("The source name you supplied has invalid characters in it. They've been replaced, please check the name still says what you want it to.");
    thistext.value = newText;
  }
  
}

