// JavaScript Document
/*
**************************************************************** 
Description: 
This  Oil Royalty Calculator JavaScript program calculates the royalty payable on Oil production given the Par Price, Well Quantity and Crown interest. 
Author: Kathleen Pate, Sept 2008 
Modification History: Nov 2008 the RoyaltyRate variable was not truncated to 4 decimals properly initially, so it was fixed. 
****************************************************************** 
*/

// Variables for decimal length.
   var DECIMALS_PAR = 2;
   var DECIMALS_QUANT = 1;
   var DECIMALS_QUANTCOMP = 2;
   var DECIMALS_ROYRATE = 2;
   var DECIMALS_RATEPAY = 4;
   var DECIMALS_CROWNINT = 7;
   var DECIMALS_PAYABLE = 1;
   function RoundAllNumber(NumberToRound,DecimalPlaces)
   {
      var newnumber = Math.round((NumberToRound)*Math.pow(10,DecimalPlaces))/Math.pow(10,DecimalPlaces);
      return newnumber;
   }
   
      function fixFloatingPointErrors(numberToFix)
   {
		fixedNumber = Number(numberToFix);
		// round to 14 decimal places to fixed floating point errors
		// this number depends on the browser.  
		// i.e. how many decimal places the browser keeps precision to
		fixedNumber = Number(fixedNumber.toFixed(14));
		return fixedNumber;
	}
	
   // Adds zeros and a decimal point if need be for visual decimal clarity
   function padDecimalZeroes(theInput, decimals)
   {
    // If exact integer, will need to add extra zeroes and a decimal point
    if(theInput.value == parseInt(theInput.value))
    {
       appendDecimalPad(theInput, true, decimals);
    }
 // If integer has decimal, will need to ascertain location of decimal point
    else
    {
       var str = "" + theInput.value;
       var decPt = str.indexOf(".");
       
       if(-1 == decPt)   //there happens to be no period
       {
          appendDecimalPad(theInput, true, decimals);
       }
       else      //no need to add period, just extra zeros to existing decimals
       {
          var currentDecimals = str.length - (decPt+1);
          appendDecimalPad(theInput, false, decimals-currentDecimals);
       }
    }
   }
   
   function appendDecimalPad(theInput, addDecimalPoint, decimals)
   {
 if(addDecimalPoint == true) //add a decimal point
 {
    theInput.value = theInput.value + ".";
  }
   //if false, then no period is added to the string just zeros
   for (i=0; i < decimals; i++) 
   { 
    theInput.value += "0"; 
   }              
 }
 
 function decimalCheck(theInput, decimals)
 {
    var str = "" + theInput;                 // Temporary string for form value
    var maxDec = decimals;                   // Maximum decimals allowed
       var decPt = str.indexOf(".");            // Position index of decimal
       var currentDecimals;                     // Returns how many decimals were typed in
       var decCheck;                           // Boolean to capture if there correct decimals
       
       if (decPt != -1)
       {
           currentDecimals = str.length - (decPt+1);
            
           if (currentDecimals > maxDec)    //There is more decimals than allowed
           {
              decCheck = false;
              // write our alert error in the code where it is called.
           }
           else
           {
              decCheck = true;
           }
       }
       else
       {
          decCheck = true;
       }
       return decCheck;
 }
  
   
   
   // Calculates the Price Component given the Par Price (PART 1)
   // Edit the Par Price field and if there are no errors (true), calculate Price Component
   function PriceComponent (form)
   {
     var ParPrice = form.ParPrice.value;
     var Messagestring = "";
  var PriceComp;
  var ReturnCode;
  
  // Error handling and verify values match business rules.
       if(isNaN(ParPrice))  {Messagestring += "The Par Price entered is not a number. \n";  }
  if(ParPrice =="") {Messagestring += "Please enter the Par Price number.  \n"; }
  if(ParPrice < 0) {Messagestring += "The Par Price may not be a negative number.   \n"; }
  
  if (Messagestring != "") 
  {
   document.NRFform.ParPrice.focus();
   alert(Messagestring);
   ReturnCode = false;
  }
  else
  {
   if (decimalCheck(ParPrice, DECIMALS_PAR)== false) //if decimal is more than two
         {
       document.NRFform.ParPrice.focus();
       alert("Par Price may only be 2 decimal places");
       ReturnCode = false;
   }
   else
   {
       ReturnCode = true;
       // Process the correct values.
       
       // Initialize fields in case the user has typed in an error.
          form.PPA.value = "";
          form.RPA.value = "";
          form.PPB.value = "";
          form.RPB.value = "";
          form.PPC.value = "";
          form.RPC.value = "";
       
       if (ParPrice > 0 && ParPrice <= 250)
       {
        form.PPA.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.PPA, DECIMALS_PAR);
        PriceComp = ((ParPrice - 190)* 0.0006)*100;
		PriceComp = fixFloatingPointErrors(PriceComp);
        form.RPA.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
        padDecimalZeroes(form.RPA, DECIMALS_PAR);
        // Repopulate the entry field
        form.ParPrice.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.ParPrice, DECIMALS_PAR);
        // Fill hidden field with the value for reference in Part 3
        form.PriceCompFinal.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
       }
       else if (ParPrice > 250 && ParPrice <= 400)
       {
        form.PPB.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.PPB, DECIMALS_PAR);
        PriceComp = (((ParPrice - 250)*0.0010)+ 0.036) *100;
		PriceComp = fixFloatingPointErrors(PriceComp);
        form.RPB.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
        padDecimalZeroes(form.RPB, DECIMALS_PAR);
        form.ParPrice.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.ParPrice, DECIMALS_PAR);
        form.PriceCompFinal.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
       }
       else if (ParPrice > 400)
       {
        form.PPC.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.PPC, DECIMALS_PAR);
        PriceComp = (((ParPrice - 400)* 0.0005)+ 0.1860)*100;
		PriceComp = fixFloatingPointErrors(PriceComp);
        form.RPC.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
        padDecimalZeroes(form.RPC, DECIMALS_PAR);
        form.ParPrice.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.ParPrice, DECIMALS_PAR);
        form.PriceCompFinal.value = RoundAllNumber(PriceComp, DECIMALS_PAR);
       }
      } //end else decimal check
        } //end else valid values
        return ReturnCode;
   }
  
   // Calculates the Well Quantity Component given the Well Production (PART 2)
   // Edit the Quantity field and if there are no errors (true), calculate Quantity Component
   function QuantityComponent(form)
   {
     var Quantity = form.WellQuantity.value;
  var QuantityComp;
  var Messagestring = "";
  var ReturnCode;
  
  // Error handling checks the value of fields so that they are within business rules
  if(isNaN(Quantity))  {Messagestring += "The well quantity entered is not a number. \n";  }
  if(Quantity == "") {Messagestring += "Please enter the Quantity.  \n"; }
  if(Quantity < 0) {Messagestring += "Well Quantity may not be a negative number. \n"; }
  
  if (Messagestring != "")
  {
      document.NRFform.WellQuantity.focus();
      alert(Messagestring);
      ReturnCode = false;
  }
  else
  {
             
      if (decimalCheck(Quantity, DECIMALS_QUANT)== false) //if decimal is more than one
      {
             document.NRFform.WellQuantity.focus();
             alert("Well Quantity may only be 1 decimal place");
             ReturnCode = false;
      }
      else
         {
             ReturnCode = true;
             
             // Process the correct values
             // Initialize blank fields in case user has typed in an error.
          form.QA.value = "";
          form.RQA.value = "";
          form.QB.value = "";
          form.RQB.value = "";
          form.QC.value = "";
          form.RQC.value = "";
          form.QD.value = "";
          form.RQD.value = "";
          
             Quantity = parseFloat(Quantity);
             if (Quantity > 0 && Quantity <= 106.4)
          {
           form.QA.value = Quantity;
           padDecimalZeroes(form.QA, DECIMALS_QUANT);
           QuantityComp = ((Quantity - 106.4)*0.0026)*100;
		   QuantityComp = fixFloatingPointErrors(QuantityComp);
           form.RQA.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
           padDecimalZeroes(form.RQA, DECIMALS_QUANTCOMP);
           //Repopulate the entry field
           form.WellQuantity.value = Quantity;
           padDecimalZeroes(form.WellQuantity, DECIMALS_QUANT)
           //Fill hidden field with the value for reference in Part 3
           form.QuantityCompFinal.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
          }
          else if (Quantity > 106.4 && Quantity <= 197.6)
          {
           form.QB.value = Quantity;
           padDecimalZeroes(form.QB, DECIMALS_QUANT);
           QuantityComp = ((Quantity - 106.4)*0.0010)*100;
		   QuantityComp = fixFloatingPointErrors(QuantityComp);
           form.RQB.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
           padDecimalZeroes(form.RQB, DECIMALS_QUANTCOMP);
           form.WellQuantity.value = Quantity;
           padDecimalZeroes(form.WellQuantity, DECIMALS_QUANT)
           form.QuantityCompFinal.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
          }
          else if (Quantity > 197.6 && Quantity <= 304.0)
          {
           form.QC.value = Quantity;
           padDecimalZeroes(form.QC, DECIMALS_QUANT);
           QuantityComp = (((Quantity - 197.6)*0.0007)+0.0912)*100;
		   QuantityComp = fixFloatingPointErrors(QuantityComp);
           form.RQC.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
           padDecimalZeroes(form.RQC, DECIMALS_QUANTCOMP);
           form.WellQuantity.value = Quantity;
           padDecimalZeroes(form.WellQuantity, DECIMALS_QUANT)
           form.QuantityCompFinal.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
          }
          else if (Quantity > 304.0)
          {
           form.QD.value = Quantity;
           padDecimalZeroes(form.QD, DECIMALS_QUANT);
           QuantityComp = (((Quantity - 304)*0.0003)+0.1657)*100;
		   QuantityComp = fixFloatingPointErrors(QuantityComp);
           form.RQD.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
           padDecimalZeroes(form.RQD, DECIMALS_QUANTCOMP);
           form.WellQuantity.value = Quantity;
           padDecimalZeroes(form.WellQuantity, DECIMALS_QUANT)
           form.QuantityCompFinal.value = RoundAllNumber(QuantityComp, DECIMALS_QUANTCOMP);
          }
          QuantityValid = true;
         } // end else Decimal Check
        } //end else valid variables
        return ReturnCode;
 }
 
 
   // Edit the Crown Interest field (onblur). If there are no errors return true.
   function verifyCrown(form)
   { 
  var Crown = form.crown.value;
  var Messagestring = "";
  var ReturnCode;
  
  // Checks the value of fields so that they are within business rules 
     if(isNaN(Crown))  {Messagestring += "The Crown interest entered is not a number. \n";  }
     if(Crown =="") {Messagestring += "Please enter the Crown interest.  \n"; }
     if(Crown < 0) {Messagestring += "Crown interest may not be a negative number. \n";}
     if(Crown > 100) {Messagestring += "Crown interest may not be more than 100. \n";}
     
     if (Messagestring != "")
  {
           document.NRFform.crown.focus();
           alert(Messagestring);
           ReturnCode = false;
       }
       else
       {
      if(decimalCheck(Crown, DECIMALS_CROWNINT) == false)
      {
         document.NRFform.crown.focus();
         Messagestring += "Crown Interest may only have 7 decimal places.";
         ReturnCode = false; 
      }
      else
      {
               ReturnCode = true;
           } 
       }//end else message string
       return ReturnCode;    
 }
 
 // Calculates the Royalty Rate (PART 3 & 4) called from the Calculate Button.
 function RoyaltyCalc (form)
 {
    // Call edit/process routines to ensure data is correct before calculating.
    if (PriceComponent(form) == true &&
         QuantityComponent(form) == true &&
         verifyCrown(form) == true)
    {
        // The data is correct, so now the processing can be executed.
        var RoyaltyRate;
        var RatePayable;
        var RoyaltyPayable;
        var Crown = form.crown.value;
        var PriceComp = form.PriceCompFinal.value;
        var QuantityComp = form.QuantityCompFinal.value;
        var Quantity = form.WellQuantity.value;
      // Calculate Royalty Rate and populate PART 3.
      if (PriceComp > 35)
      {
       form.PriceComp.value = "35.00";
       PriceComp = 35;
      }
      else
      {
       form.PriceComp.value = PriceComp;
       padDecimalZeroes(form.PriceComp, DECIMALS_ROYRATE);
      }
      
      if (QuantityComp > 30)
      {
       form.QuantityComp.value = "30.00";
       QuantityComp = 30;
      }
      else
      {
       form.QuantityComp.value = QuantityComp;
       padDecimalZeroes(form.QuantityComp, DECIMALS_ROYRATE);
      }
      // Ensure Royalty Rate is not a negative number and not more than 50 percent.
	  RoyaltyRate = Math.min(50.00,parseFloat(PriceComp) + parseFloat(QuantityComp));     
      if (RoyaltyRate < 0)
      {
       RoyaltyRate = 0;
      }
      form.RoyaltyRate.value = RoundAllNumber(RoyaltyRate, DECIMALS_ROYRATE);
      padDecimalZeroes(form.RoyaltyRate, DECIMALS_ROYRATE);
      
      /*Calculate Royalty Payable and populate PART 4
        SubTotal = Quantity x Royalty Rate */
      form.WellQuantity2.value = Quantity;
      form.RoyaltyRate2.value = RoundAllNumber(RoyaltyRate, DECIMALS_ROYRATE);
      padDecimalZeroes(form.RoyaltyRate2, DECIMALS_ROYRATE);
      RatePayable = (Quantity * RoyaltyRate)/100;
	  RatePayable = fixFloatingPointErrors(RatePayable);
	  RatePayable = RoundAllNumber(RatePayable, DECIMALS_RATEPAY);
	  form.RatePayable.value = RatePayable;
      padDecimalZeroes(form.RatePayable, DECIMALS_RATEPAY);
      
      //Multiply the Royalty Payable (subtotal) by the Crown Interest
      form.crown2.value =  RoundAllNumber(Crown, DECIMALS_CROWNINT);
      // Repopulate the entry field
      form.crown.value = RoundAllNumber(Crown, DECIMALS_CROWNINT);
      padDecimalZeroes(form.crown2, DECIMALS_CROWNINT);
      padDecimalZeroes(form.crown, DECIMALS_CROWNINT);
	  RoyaltyPayable = (RatePayable * Crown)/100;
      form.RoyaltyPayable.value = RoundAllNumber(RoyaltyPayable, DECIMALS_CROWNINT);
      padDecimalZeroes(form.RoyaltyPayable, DECIMALS_CROWNINT);
      //Truncate Royalty Payable to one decimal
      form.RoyaltyPayable1.value = RoundAllNumber(RoyaltyPayable, DECIMALS_PAYABLE);
      padDecimalZeroes(form.RoyaltyPayable1, DECIMALS_PAYABLE);
      //Focus moves to bottom of the long form for the answer. 
      document.NRFform.RoyaltyPayable1.focus();
     } 
 }
