// JavaScript Document
/* 
****************************************************************
Description:
This Transitional Oil Royalty Calculator JavaScript program calculates the royalty payable on Oil production given the Par Price, Well Quantity and Crown interest. The rates are from the Transitional plan of the new Royalty Framework.
Author: Kathleen Pate, Sept 2008
Modification History: April 2009 Changed the rates from the nrf calculator to reflect the transitional rates.
******************************************************************
*/

 // 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;
   // Rounds the number against the variable passed 
   function RoundAllNumber(NumberToRound,DecimalPlaces)
   {
      var newnumber = NumberToRound;
	  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.ARF2form.ParPrice.focus();
   alert(Messagestring);
   ReturnCode = false;
  }
  else
  {
   if (decimalCheck(ParPrice, DECIMALS_PAR)== false) //if decimal is more than two
         {
       document.ARF2form.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 - 210)* 0.00035)*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 <= 350)
       {
        form.PPB.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.PPB, DECIMALS_PAR);
        PriceComp = (((ParPrice - 250)*0.00010)+ 0.0140) *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 > 350)
       {
        form.PPC.value = RoundAllNumber(ParPrice, DECIMALS_PAR);
        padDecimalZeroes(form.PPC, DECIMALS_PAR);
        PriceComp = (((ParPrice - 350)* 0.00005)+ 0.0240)*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.ARF2form.WellQuantity.focus();
      alert(Messagestring);
      ReturnCode = false;
  }
  else
  {
             
      if (decimalCheck(Quantity, DECIMALS_QUANT)== false) //if decimal is more than one
      {
             document.ARF2form.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 <= 30.4)
          {
           form.QA.value = Quantity;
           padDecimalZeroes(form.QA, DECIMALS_QUANT);
           QuantityComp = ((Quantity - 30.4)*0.0013)*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 > 30.4 && Quantity <= 152.0)
          {
           form.QB.value = Quantity;
           padDecimalZeroes(form.QB, DECIMALS_QUANT);
           QuantityComp = ((Quantity - 30.4)*0.0013)*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 > 152.0 && Quantity <= 273.6)
          {
           form.QC.value = Quantity;
           padDecimalZeroes(form.QC, DECIMALS_QUANT);
           QuantityComp = (((Quantity - 152.0)*0.0008)+0.1581)*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 > 273.6)
          {
           form.QD.value = Quantity;
           padDecimalZeroes(form.QD, DECIMALS_QUANT);
           QuantityComp = (((Quantity - 273.6)*0.0002)+0.2554)*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.ARF2form.crown.focus();
           alert(Messagestring);
           ReturnCode = false;
       }
       else
       {
      if(decimalCheck(Crown, DECIMALS_CROWNINT) == false)
      {
         document.ARF2form.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 > 35)
      {
       form.QuantityComp.value = "35.00";
       QuantityComp = 35;
      }
      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.ARF2form.RoyaltyPayable1.focus();
     } 
 }
   
