/*
   EMI Fret-Placement Calculator and Free-Bar Lenght Calculator
   Design: Bart Hopkin and Bret Parsons
   JavaScript: Bret Parsons
*/
MAXTONES = 72;

function trunc(n) {
   var place = 100000;
   return Math.round(place*(n))/place;
   }

function floatFix(val, places) {
   var res = "" + Math.round(val * Math.pow(10, places));
   var dec = res.length - places;
   if (places != 0 )
      return res.substring(0, dec) + "." + res.substring(dec, res.length);
   else
      return res;
   }

function fretCalc (
   fScaleLength,  // the length of the string
   iNumFrets,     // number of frets to calculate
   iNumTones,     // number of tones in scale
   afResults      // array to return results, fFretDestBridge,fFretDistNut
   ) {

   var fFretDistBridge;      // calculated fret distance from bridge
   var fFretDistNut;         // calculated fret distance from nut
   var fInverseScaleFactor;  // calculated value for determining frets
   var iCurFret;

   fFretDistBridge = fScaleLength;
   fInverseScaleFactor= 1/Math.pow(2,1/iNumTones);
   for (iCurFret = 0; iCurFret < iNumFrets; iCurFret++) {
      fFretDistBridge *= fInverseScaleFactor;
      fFretDistNut = fScaleLength - fFretDistBridge;
      afResults[iCurFret][0] = fFretDistNut;
      afResults[iCurFret][1] = fFretDistBridge;
      }
   }

function fretCalcWithStretchCompensation (
   fScaleLength, // the length of the string
   iNumFrets,    // number of frets to calculate
   iNumTones,    // number of tones in scale
   afResults     // array to return results, fFretDestBridge,fFretDistNut
   ) {

   var fFretDistBridge;      // calculated fret distance from bridge
   var fFretDistNut;         // calculated fret distance from nut
   var fCompensationFactor;  // calculated Stretch Compensation Factor
   var fInverseScaleFactor;  // calculated value for determining frets
   var iCurFret;
   var fFretDistBridgeCompensated;

   fFretDistBridge = fScaleLength;
   fFretDistNut = 0;
   fInverseScaleFactor= 1/Math.pow(2,1/iNumTones);
   for (iCurFret = 0; iCurFret < iNumFrets; iCurFret++) {
      fFretDistBridge *= fInverseScaleFactor;
      fFretDistNut = fScaleLength - fFretDistBridge;
      if (fFretDistNut / fScaleLength < 0.168)
         fCompensationFactor = 0.0833 * (fFretDistNut / fScaleLength) + 0.980;
      else
         fCompensationFactor = 0.994;

      fFretDistNut *= fCompensationFactor;
      fFretDistBridgeCompensated = fScaleLength - fFretDistNut;

      afResults[iCurFret][0] = fFretDistNut;
      afResults[iCurFret][1] = fFretDistBridgeCompensated;
      }
   }

function setUpVariablesAndHtmlAndGo(theForm) {
   var fScaleLength = parseFloat(theForm.scaleLength.value);
   if (isNaN(fScaleLength)) {
      document.getElementById('fpResults').innerHTML = "<div class='err'>Error! Scale length needs to be a number.</div>";
      return;
      }

   var sUnits, bInches = theForm.unitsChoice[0].checked
   if (bInches)
      sUnits = "In."
   else
      sUnits = "Cm.";

   var iNumTones=parseFloat(theForm.numberTones.value);
   if (isNaN(iNumTones)) {
      document.getElementById('fpResults').innerHTML = "<div class='err'>Error! Number of Tones needs to be a number.</div>";
      return;
      }
   if (iNumTones > MAXTONES) {
      document.getElementById('fpResults').innerHTML = "<div class='err'>Error! Number of Tones cannot be greater than" + MAXTONES + ".</div>";
      return;
      }
   var iNumFrets = 2 * iNumTones;

   // set up two dimensional array to hold resuts
   var afResults = new Array(iNumFrets);
   for (i = 0; i < iNumFrets; i++)
      afResults[i] = new Array(2);
   var bStretchCompensation=theForm.stretchComp.checked;


   var output = "";
   output += '<table class="frets">';
   output += '<tr><td colspan="3" class="hdr">Fret Placement Results<br/>'
      + 'Scale Length = ' + fScaleLength + ' ' + sUnits + '<br/>'
      + iNumTones + ' Tone Equal Temperament<br/>'
      + 'Uncompensated Scale Factor = 0' + floatFix(1/Math.pow(2,1/iNumTones),4);
   if (bStretchCompensation)
      output += '<br/>Stretch Compensated For';
   output += '</td></tr>';
   output += '<tr><td class="hdr">Fret</td><td class="hdr">Distance From Nut</td><td class="hdr">Distance From Bridge</td></tr>';

   if (bStretchCompensation)
      fretCalcWithStretchCompensation (fScaleLength, iNumFrets, iNumTones, afResults);
   else
      fretCalc(fScaleLength, iNumFrets, iNumTones, afResults);

   for (iCurFret = 0; iCurFret < iNumFrets; iCurFret++){
      nonComputerFret = iCurFret + 1;  // The real would compensation
      output += '<tr><td>' + nonComputerFret + '</td><td>' + floatFix(afResults[iCurFret][0], 4) + '</td><td>'
           + floatFix(afResults[iCurFret][1], 4) + '</td></tr>';
      }

   output += '</table>';
   document.getElementById('fcResults').innerHTML = output;
   }


function windworld_etStart (theForm){
   var nTonesPerOctave = theForm.elements[0].value;
   var sampleBarLength  = theForm.elements[1].value;
   var nStepsAbove = theForm.elements[2].value;
   var nStepsBelow = theForm.elements[3].value;

   if (nTonesPerOctave == 0 || nTonesPerOctave == "0") {
      document.getElementById('etResults').innerHTML = "<div class='err'>You must have a sample bar length.</div>";
      return;
      }
   if (sampleBarLength == 0 || sampleBarLength == "0") {
      document.getElementById('etResults').innerHTML = "<div class='err'>You must have a sample bar length.</div>";
      return;
      }
   else if ((nStepsBelow == 0 || nStepsBelow == "0") && (nStepsAbove == 0 || nStepsAbove == "0")) {
      document.getElementById('etResults').innerHTML = "<div class='err'>You don't have any steps to calculate.</div>";
      return;
      }

   var output = "";
   output += '<table border="0" cellpadding="3" cellspacing="3">';
   output += '<tr><td class="hdr" colspan="2">Calculator Results</td></tr>';
   output += '<tr><td class="hdr">Bar</td><td class="hdr">Length of Bar</td></tr>';

   // calculate steps below octave
   var i = 0;
   var newValue = 0;
   var prevL = sampleBarLength;
   var resultsArry = new Array(nStepsBelow);
   for (i = 0; i < nStepsBelow; i++) {
      newValue = (Math.pow(2,(1/(2*nTonesPerOctave)))*prevL);
      resultsArry[i] = trunc(newValue);
      prevL = newValue;
      }

   // write steps below octave to screen
   for (i = (nStepsBelow-1); i >= 0; i--)
      output += '<tr><td>-' + (i+1) + '</td><td>' + resultsArry[i] + '</td></tr>';

   // write sample bar length to screen
   output += '<tr><td>' + "Sample&nbsp;Bar" + '</td><td>' + sampleBarLength + '</td></tr>';

   // calculate steps above octave
   prevL = sampleBarLength;
   for (i = 0; i < nStepsAbove; i++) {
      newValue = (Math.pow(.5,(1/(2*nTonesPerOctave)))*prevL);
      output += '<tr><td>' + (1+i) + '</td><td>' + trunc(newValue) + '</td></tr>';
      prevL = newValue;
      }
   output += '</table>';

   document.getElementById('etResults').innerHTML = output;
   }


function windworld_addBar(theForm) {
   var output = "";
   output += '<table class="fbc2" border="0" cellpadding="3" cellspacing="3">';
   output += '<tr><td width="50%"><input name="scaleLength" size="2" type="text" /><em>&nbsp;/&nbsp;</em><input name="scaleLength" size="2" type="text" /></td>';
   output += '<td><input name="scaleLength" size="7" type="text" /></td></tr>';
   output += '</table>';
   document.getElementById('newButtons').innerHTML += output;
   }


function windworld_jiStart(theForm) {
   var i, c = 0, d = 0, L = 0;

   var done = false;
   var theFormLength = (theForm.elements.length) - 2;

   // find the first sample bar and ratio:
   for (i = 0; (i < theFormLength) && !done; i += 3) {
      if (theForm.elements[i+2].value!='') {
         L = (theForm.elements[i+2].value);
         c = theForm.elements[i].value;
         d = theForm.elements[i+1].value;
         done = true;
         }
      }

   if (c == 0 || d == 0 || L == 0 || c == "0" || d == "0" || L == "0") {
      if (L == 0 || L == "0")
         document.getElementById('jiResults').innerHTML = "<div class='err'>You have not entered a starting bar length.</div>";
      else if (c == 0 || d == 0 || c == "0" || d == "0")
         document.getElementById('jiResults').innerHTML = "<div class='err'>You can not have a ratio containing a zero or a blank.</div>";
      return;
      }

   //set up an array of results
   var numEntries = theFormLength/3;
   var resultsArray = new Array(numEntries);
   var a = 0, b = 0, j = 0, prevSmallIndex, prevSmallValue;

   for (i = 0; i < theFormLength; i+=3) {
      // current ratios
      a  = theForm.elements[i].value
      b  = theForm.elements[i+1].value

      // if the bar length is given for this ratio - use it
      if (theForm.elements[i+2].value!='') {
         c = theForm.elements[i].value;
         d = theForm.elements[i].value;
         prevSmallIndex = i;
         }
      // otherwise, find the closest given bar length for the ratio being working on
      else {
         // find sample bar and ratio:
         prevSmallValue = Number.MAX_VALUE;
         prevSmallIndex = 0;
         for (sampLoop=0; (sampLoop<theFormLength); sampLoop+=3) {
            if(theForm.elements[sampLoop+2].value!='') {
               c = theForm.elements[sampLoop].value;
               d = theForm.elements[sampLoop+1].value;

               //alert("i: " + i + "\n prevSmallValue: " + trunc(prevSmallValue) + ", curval: " + Math.abs((a/b)-(c/d)) + "\n (a/b)-(c/d): " + a+"/"+b + "-"+c+"/"+d);
               if(prevSmallValue >= Math.abs((a/b)-(c/d))) {
                  prevSmallValue = Math.abs((a/b)-(c/d));
                  prevSmallIndex = sampLoop;
                  }
               }
            }
         }

      // alert("prevSmallIndex: " + prevSmallIndex + "\n using (a/b)-(c/d): " + a+"/"+b + "-"+c+"/"+d);
      c = theForm.elements[prevSmallIndex].value;
      d = theForm.elements[prevSmallIndex+1].value;
      L = (theForm.elements[prevSmallIndex+2].value);

      // L1 = [sqrt(bc/ad)]*L
      var val = trunc(Math.sqrt((b*c)/(a*d)) * L) ;
      val = val + "";
      if (val == "NaN") {
         val = "&nbsp;";
         }
      resultsArray[j++] = val;
      if (theForm.elements[i].value == "")
         break;
      }

   var j = 0;
   var output = "";
   output += '<table border="0" cellpadding="3" cellspacing="3">';
   output += '<tr><td class="hdr" colspan="2">Calculator Results (JI)</td></tr>';
   output += '<tr><td class="hdr">Ratios</td><td class="hdr">Length of Bar</td></tr>';
   for (i=0; i< theFormLength; i+=3) {
      if (resultsArray[j] == "&nbsp;")
         break;
      output += '<tr><td>' + theForm.elements[i].value + '/' + theForm.elements[i+1].value + '</td>';
      output += '<td>' + resultsArray[j++] + '</td></tr>';
      }
   output += '</dl>';

   document.getElementById('jiResults').innerHTML = output;
   }
