/*******************************************************
 *  fees.calculator 
 *
 *  Facilitates the calculation of fees and payment schedules for
 *  Boundary Bay Montessori House
 *
 *  Copyright (c) 2009 Simon Shutter and Schemax Design (www.schemax.com)
 *
 *  Dislaimer : Any use of this software is the responsibility of the user
 *              Simon Shutter and Schemax Design have developed this tool for 
 *              free for the use of BBMH, MIND and its members and are not
 *              responsible for any errors or omissions herein.
 *
 *  Version Date      Notes
 *  0.0.1   Feb 18/09 Initial release
 *  0.0.2   Feb 20/09 Added error messages to enforce order of children is descending program
 *  1.0.0   Feb 4/10  Updated fees
 */

$(document).ready(function(){
            
function CalculateFeesForFamily(family,newEnrollment,paymentOption){

    // BBMH Fees Calculator
    // calculate fees per family

    // takes an array of 3 children (indices 1 or 2 may be null)
    // assume array is sorted in descending order of age
    // dates assume that calculations are for September of current calendar year

    // define selector for output
    var feesDetails = $("#feesDetails");
    
    // grades
    var grade = {elm: "Elementary", fdk: "Full Day Kindergarten", pre: "Preschool"};
    
    // fees
    var fees = {
                    firstVolunteerHours :   {elm: 500, fdk : 500, pre: 250},
                    secondVolunteerHours :  {elm: 700, fdk : 700, pre: 350},
                    firstNRD :              {elm: 370, fdk : 370, pre: 300},
                    secondNRD :             {elm: 370, fdk : 370, pre: 275},
                    siblingDiscount :       {elm: 500, fdk: 500, pre: 250},
                    tuition :               {elm: 5100, fdk : 5100, pre: 3990}
                };
                
    // define ordinals for age rank of child in family
    var nth = {1 : "first", 2 : "second", 3 : "third"};
    
    // payment option discounts (values are fractions of 1 ie 0.05 = 5%)
    var paymentOptionDiscount = {one : -0.05, three : 0,ten :0.02};
    
    // define year school starts and ends
    var now = new Date()
    var yearSchoolStarts = now.getFullYear();
    var yearSchoolEnds = yearSchoolStarts + 1;
    
    // determine last working day in February
    var lastWorkingDateInFebruary = LastWorkingDateInFebruary(yearSchoolStarts);

    // define installment dates in array - the elements act as a key for installmentDateAmounts
    // (not all are used in each scenario - depends on payment option)
    var installmentDates = [
          lastWorkingDateInFebruary,             // first NRD, emergency kit and MIND membership
          "June 1, " + yearSchoolStarts,         // second NRD
          "July 1, " + yearSchoolStarts,         // one time payment option installment or first of the three installments option
          "September 1, " + yearSchoolStarts,    // first of the monthly installments option
          "October 1, " + yearSchoolStarts,      // second of the monthly installments option
          "November 1, " + yearSchoolStarts,     // third of the monthly installments option
          "December 1, " + yearSchoolStarts,     // fourth of the monthly installments option
          "December 31, " + yearSchoolStarts,    // first volunteer hours deposit
          "January 1, " + yearSchoolEnds,        // fifth monthly installment or second of the three installments option
          "February 1, " + yearSchoolEnds,       // sixth of the monthly installments option
          "March 1, " + yearSchoolEnds,          // seventh of the monthly installments option
          "April 1, " + yearSchoolEnds,          // eighth of the monthly installments option or third of the monthly installments option
          "May 1, " + yearSchoolEnds,            // ninth of the monthly installments option
          "June 1, " + yearSchoolEnds            // tenth of the monthly installments option or second volunteer hours deposit
    ]

    // define installments, using installment dates as keys because they can be used to iterate the installment object in order.
    var installments = {};
    
    // initiate installment amounts that are used to aggregate fees for each installment
    for (var i=0;i<installmentDates.length;i++)
    {
      // define an object literal for each installment date
      installments[installmentDates[i]] = {};
      
      // add an amount to aggregate total fees at each installment
      installments[installmentDates[i]].amount = 0;
      
      // add an amount to aggregate refundable fees eg volunteer hours
      installments[installmentDates[i]].refundable = 0;

      // add an amount to aggregate non-refundable fees eg fee deposits
      installments[installmentDates[i]].nonRefundable = 0;
    }
    
    var subtext = "";
    var txt = "<p>Note: all cheques should be made out to MIND.</p><div class='feeNarrative'>";
    //if first time enrollment pay $100
    if (newEnrollment == true)
    {
        subtext += "First time families are required to pay $100";
    }
    
    //pay $50 for MIND membership on last Friday of Feb
    subtext += "The annual family membership for MIND society is $50 and is due on " + lastWorkingDateInFebruary + ". ";
    installments[lastWorkingDateInFebruary].amount += 50;

    //calculate volunteer post-dated cheques = f(grade of oldest child)
    
    // oldest child always first item in array
    subtext += "You are required to provide two post-dated cheques in case you are unable to meet your obligations for volunteer hours during the year. ";
    
    // post-dated cheques
    var firstVolunteerHours = fees.firstVolunteerHours[family[0]];
    var secondVolunteerHours = fees.secondVolunteerHours[family[0]];
    subtext += "Since your" + (family.length > 1 ? " oldest":"")  + " child is entering the " + grade[family[0]] + 
           " program please write one cheque dated December 31, " + yearSchoolStarts + " for $" +
           readableNumberLimiter(Math.round(firstVolunteerHours),',') + 
           " and a second cheque dated June 1, " + yearSchoolEnds + " for $" +
           readableNumberLimiter(Math.round(secondVolunteerHours),',') + ".";
    installments["December 31, " + yearSchoolStarts].amount += firstVolunteerHours;
    installments["June 1, " + yearSchoolEnds].amount += secondVolunteerHours;
    // add the volunteer fees as refundable 
    installments["December 31, " + yearSchoolStarts].refundable += firstVolunteerHours;
    installments["June 1, " + yearSchoolEnds].refundable += secondVolunteerHours;
    
    txt += "<p>" + subtext + "</p>";
    
    //
    // calculate fees for each child
    //
    txt += "<p>The fees for" +  (family.length > 1 ? " each child":" your child") + " are as follows:</p>";

    // interate over children in family
    for (var i=0; i < family.length; i++)
    {
        subtext = "";
        
        // get child
        var child = family[i];
 
        subtext+= "Your " + (family.length > 1 ? nth[i+1] : "") + " child is entering the " + grade[child] + " Program.";
        txt += "<p class='childSubtitle'>" + subtext + "</p>";
 
        subtext ="";
        
        // pay $20 for emerg kit on last Friday of Feb
        subtext+= "There is an annual fee for the emergency kit of $20/child, " + 
                  "which is also due on " + lastWorkingDateInFebruary + ". ";
        installments[lastWorkingDateInFebruary].amount += 20;
        
        // pay NRD = f(grade)
        subtext+= "To guarantee your child's enrollment, two non-refundable deposits are required as follows. ";
        
        // define tuition fee and non-refundable deposit
        var firstNRD = fees.firstNRD[child];
        var secondNRD = fees.secondNRD[child];
        subtext+= "The first deposit for $" + readableNumberLimiter(Math.round(fees.firstNRD[child]),',') + 
                  " is due on " + lastWorkingDateInFebruary  + 
                  " and the second deposit for $" + readableNumberLimiter(Math.round(fees.secondNRD[child]),',') +
                  " is due on June 1, " + yearSchoolStarts + ". ";
        installments[lastWorkingDateInFebruary].amount += firstNRD;
        installments["June 1, " + yearSchoolStarts].amount += secondNRD;

        // add the deposits as non-refundable
        installments[lastWorkingDateInFebruary].nonRefundable += firstNRD;
        installments["June 1, " + yearSchoolStarts].nonRefundable += secondNRD;
        
        // remaining fees = fees - NRD fees - discount
        var tuition = fees.tuition[child];
        var net = tuition - fees.firstNRD[child] - fees.secondNRD[child];
       
        subtext+= "Your child's overall tuition for the " + yearSchoolStarts + "-" + yearSchoolEnds + " school year is $" + readableNumberLimiter(Math.round(tuition),',') + ". " + 
                  "The balance of tuition after subtracting the two non-refundable deposits is $" +
                  readableNumberLimiter(Math.round(net),',') + ". ";



        // check if child is a sibling and therefore entitled to a discount
        var discount = i > 0 ? fees.siblingDiscount[child]: 0;
        var discountedFees = net - discount;
                
        if(discount > 0){
              subtext+= "Your child is a sibling of an older child at the school and is entitled to a discount of $" +
                        readableNumberLimiter(Math.round(discount),',') + ". " +
                        "Therefore the balance after subtracting the discount is $" + 
                        readableNumberLimiter(Math.round(discountedFees),',') + ". ";
        }
        txt += "<p>" + subtext + "</p>";

        // adjust fees based on payment option
        var adjusted = discountedFees + (discountedFees * paymentOptionDiscount[paymentOption]);

        subtext = "";      
        
        // installments = f(remaining fees, payment option)
        switch(paymentOption){
            case "one":
                // case one time
                // adjusted fees = remaining fees  - 5% remaining fees
                // pay adjusted fees on first of Jul
                subtext+=   "<p>You have selected the one time payment option and are therefore entitled to a 5% reduction " +
                            "on the balance of your child's tuition. The reduced amount is $" + 
                            readableNumberLimiter(Math.round(adjusted),',') +
                            " and is payable by cheque on July 1, " + yearSchoolStarts + ".</p>";
                installments["July 1, " + yearSchoolStarts].amount += adjusted;
                break;
                
            case "three":
                // case three installments
                // adjusted fees = remaining fees
                // pay 40% adjusted fees on first of Jul
                // pay 30% adjusted fees on first of Jan
                // pay 30% adjusted fees on first of Apr
                var installment1 = 0.4 * adjusted;
                var installment2 = 0.3 * adjusted;
                var installment3 = 0.3 * adjusted;
                
                subtext+= "<p>You have selected the three installments payment option. " + 
                          "The installment amounts and dates are as follows:</p>";
                subtext+= "<ol>";
                subtext+= "<li>$" + readableNumberLimiter(Math.round(installment1),',') + " (40%) dated July 1, " + yearSchoolStarts + "</li>";
                subtext+= "<li>$" + readableNumberLimiter(Math.round(installment2),',') + " (30%) dated January 1, " + yearSchoolEnds + "</li>";
                subtext+= "<li>$" + readableNumberLimiter(Math.round(installment3),',') + " (30%) dated April 1, " + yearSchoolEnds + "</li>";
                subtext+= "</ol>";
                installments["July 1, " + yearSchoolStarts].amount += installment1;
                installments["January 1, " + yearSchoolEnds].amount += installment2;
                installments["April 1, " + yearSchoolEnds].amount += installment3;
                
                break;
                
            case "ten":
                // case ten installments
                // adjusted fees = remaining fees + 2% remaining fees
                var installment = 0.1 * adjusted;

                subtext+= "<p>You have selected the ten monthly installments payment option, which is subject to a 2% finance charge. " +
                      "The adjusted amount is " +  readableNumberLimiter(Math.round(adjusted),',') + "." +
                      "The installment amounts and dates are as follows:</p>";
                subtext+= "<ol>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated September 1, " + yearSchoolStarts + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated October 1, " + yearSchoolStarts + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated November 1, " + yearSchoolStarts + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated December 1, " + yearSchoolStarts + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated January 1, " + yearSchoolEnds + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated February 1, " + yearSchoolEnds + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated March 1, " + yearSchoolEnds + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated April 1, " + yearSchoolEnds + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated May 1, " + yearSchoolEnds + "</li>";
                subtext+=  "<li>$" + readableNumberLimiter(Math.round(installment),',') + " dated June 1, " + yearSchoolEnds + "</li>";
                subtext+= "</ol>";
                
                installments["September 1, " + yearSchoolStarts].amount += installment;
                installments["October 1, " + yearSchoolStarts].amount += installment;
                installments["November 1, " + yearSchoolStarts].amount += installment;
                installments["December 1, " + yearSchoolStarts].amount += installment;
                installments["January 1, " + yearSchoolEnds].amount += installment;
                installments["February 1, " + yearSchoolEnds].amount += installment;
                installments["March 1, " + yearSchoolEnds].amount += installment;
                installments["April 1, " + yearSchoolEnds].amount += installment;
                installments["May 1, " + yearSchoolEnds].amount += installment;
                installments["June 1, " + yearSchoolEnds].amount += installment;
                
                break;
        }
        txt += subtext;
    }    
    subtext = "<p>The following table of fee installments is intended to help you draft your post-dated cheques.</p>";
    
    // create a table that is a header for the family
    var tableSummary = "<table class='summaryTable'><tr><th>Installment Date</th><th>Amount</th><th>Notes</th></tr>";
    
    // summarize payment schedule for family
    // for each installment, list cheque amount
    var installmentNote = "";
    var installmentDate = "";
    var subtotal = 0;
    var refundable = 0;
    var nonRefundable = 0;
    var total = 0;
    
    for(var i=0;i<installmentDates.length;i++){
        installmentDate = installmentDates[i];
        subtotal = installments[[installmentDate]].amount;
        refundable = installments[[installmentDate]].refundable;
        nonRefundable = installments[[installmentDate]].nonRefundable;
        installmentNote = "";
        if (refundable > 0)
        {
            installmentNote += "Includes $" + readableNumberLimiter(Math.round(refundable),',') + " that is only cashed if you are unable to meet your volunteer commitments. ";
            if (refundable < subtotal){
                installmentNote += "Please draft separate cheque.";
            }
        }
        if (nonRefundable > 0)
        {
            installmentNote += "Includes $" + readableNumberLimiter(Math.round(nonRefundable),',') + " non-refundable fees. ";
        }
        // only add installment date and amount if it exists - installment dates depend on payment option
        if(subtotal > 0){
          total+= subtotal;
          tableSummary+= "<tr>";
          tableSummary+= "<td class='installmentDate'>" + installmentDate + "</td>";
          tableSummary+= "<td class='installmentAmount'>" + "$" + readableNumberLimiter(Math.round(subtotal),',') + "</td>";
          tableSummary+= "<td class='installmentNote'>" + installmentNote + "</td>";
          tableSummary+= "</tr>";
        }
    }
    tableSummary+= "<tr>";
    tableSummary+= "<td style='text-align:right;'>TOTAL</td>";
    tableSummary+= "<td class='installmentTotal'>" + "$" + readableNumberLimiter(Math.round(total),',') + "</td>";
    tableSummary+= "<td>&nbsp;</td>";
    tableSummary+= "</tr>";
    tableSummary+= "</table>";
    subtext += tableSummary;
    txt += subtext;
    txt += "</div>";
    
    feesDetails.append(txt);
    
    total = "$" + readableNumberLimiter(Math.round(total),',');
    return total;
}

// Used by feeCalculator.aspx to calculate fees for a single family
$("#calculate").click( function(){
    InitiateFeesCalculation();

      // prevent form from being submitted to server
      return false;
});

function InitiateFeesCalculation(){

      var oldest = $("#oldest :selected").val();
      var middle = $("#middle :selected").val();
      var youngest = $("#youngest :selected").val();

      // check that a youngest child has two older siblings
      if (middle == "none" && youngest != "none")
      {
          alert("If you select a third child you must also select a second child !");
          return false;
      }
      
      // check that children are selected in order
      // rules :  if third child is in older class that second or first then error
      //          if second child is in older class that first then error
      
      // use object literal
      var program = {"elm":3, "fdk":2, "pre":1};
      
      switch(true){
        case program[youngest]>program[oldest]:
          alert("Third child cannot be in a program that is above first child");
          return;
          break;
        case program[youngest]>program[middle]:
          alert("Third child cannot be in a program that is above second child");
          return;
          break;
        case program[middle]>program[oldest]:
          alert("Second child cannot be in a program that is above first child");
          return;
          break;
      }
      
      
      // get all student combinations
      var family = [];
      $('.student :selected').each(
                                      function(i, selected){
                                        var svalue = $(selected).val();
                                        if (svalue != "none"){
                                          family[i] = svalue
                                        }
                                      }
                                   );
  
      // define each family as having already enrolled children in the past
      var newEnrollment = new Boolean(false);
      
      // get the payment option
      var paymentOption = $("#paymentOption").val();
      
      // show the results heading
      $("#feesDetailsHeading").show();
      
      // clear the fee details sections
      var feesDetails = $("#feesDetails");
      feesDetails.empty();
      
      // calculate fees and generate HTML
      var total = CalculateFeesForFamily(family,newEnrollment,paymentOption);

}

// Used by feeCalculatorAll.aspx to calculate fees for a single family
RunUnitTests = function (){

    //Purpose : test families with different combination of up to 3 children at BBMH
    //sorted in descending grade

    // define families
    var families = [
        // families with one child
        ["pre"],
        ["fdk"],
        ["elm"],
        // families with two children
        ["pre", "pre"],
        ["fdk", "pre"],
        ["elm", "pre"],
        ["fdk", "fdk"],
        ["elm", "fdk"],
        ["elm", "elm"],
        // families with three children
        ["pre", "pre","pre"],
        ["fdk", "pre","pre"],
        ["elm", "pre","pre"],
        ["fdk", "fdk","pre"],
        ["elm", "fdk","pre"],
        ["elm", "elm","pre"],
        ["fdk", "fdk","fdk"],
        ["elm", "fdk","fdk"],
        ["elm", "elm","fdk"],
        ["elm", "elm","elm"]
    ];
    
    // define each family as having already enrolled children in the past
    var newEnrollment = new Boolean(false);
    
    // report the family scenarios
    var feesDetails = $("#feesDetails");
    var tableOfContentsBody = "";
    var familyCount = families.length;
    var paymentOptions = {  1: {brief :"one", full : "One Payment"},
                            2: {brief :"three", full : "Three Payments"},
                            3: {brief :"ten", full : "Ten Monthly Payments"}
                         };
    
    var paymentOptionFees = new Array(3);
    
    for (var i=0; i<familyCount; i++)
    {
        var family = families[i];

        for (var optionCounter=1; optionCounter<=3; optionCounter++)
        {
            var paymentOption = paymentOptions[optionCounter].brief;

            // create an in-page link to top
            feesDetails.append("<div class='feesNavToTop' id='f" + i + paymentOption + "'><a alt='jump to top of page' href='#wrapper'>top</a></div>");

            // create a table that is a header for the family
            var tableOfThisFamily = "<table class='familyMakeup'>" + 
                                    "<tr><th>First Child</th><th>Second Child</th><th class='borderRight'>Third Child</th>" + 
                                    "<th>Number of Installments</th></tr>";
            tableOfThisFamily+= "<tr>";
            // two oldest children columns
            for (var j=0; j<2; j++)
            {
                tableOfThisFamily+= "<td>";
                tableOfThisFamily+= family[j] != null ? family[j] : "&nbsp;" ;
                tableOfThisFamily+= "</td>";
            }
            // youngest child columns
            tableOfThisFamily+= "<td class='borderRight'>";
            tableOfThisFamily+= family[2] != null ? family[2] : "&nbsp;" ;
            tableOfThisFamily+= "</td>";
            
            tableOfThisFamily+= "<td>" + paymentOption + "</td>";
            tableOfThisFamily+= "</tr>";
            tableOfThisFamily+= "</table>";
            feesDetails.append(tableOfThisFamily);
           
            paymentOptionFees[optionCounter] = CalculateFeesForFamily(family,newEnrollment,paymentOption);
        }
        
        tableOfContentsBody += "<tr>";
        // two oldest children columns
        for (var j=0; j<2; j++)
        {
            var child = family[j];
            var cell = child != null ? child : "&nbsp;" ;
            tableOfContentsBody+= "<td>" + cell + "</td>";
        }
        // youngest child columns
        var child = family[2];
        var cell = child != null ? child : "&nbsp;" ;
        tableOfContentsBody+= "<td class='borderRight'>" + cell + "</td>";
        
        // add links to each combination of family and payment option
        for (var optionCounter=1; optionCounter<=3; optionCounter++)
        {
          var total = paymentOptionFees[optionCounter];
          tableOfContentsBody+= "<td class='alignRight'>" +"<a href = #f" + i + paymentOptions[optionCounter].brief + ">" + total + "</a>" + "</td>";
        }
        tableOfContentsBody+= "</tr>";
    }
    $("#tableBody").append(tableOfContentsBody);
    
    // zebra stripe the table
    $("#tableBody tr:nth-child(even) td").addClass("even");
}

readableNumberLimiter = function (number,limiter)
{
  return number.toString().replace(
    new RegExp(
                "(^\\d{"+(number.toString().length%3||-1)+"})(?=\\d{3})"),
                "$1"+limiter
              ).replace(/(\d{3})(?=\d)/g,"$1"+limiter);
}

// Used by parents.aspx to update the current school year
UpdateCurrentYear = function (){

    // define year school starts and ends
    var now = new Date()
    var yearSchoolStarts = now.getFullYear();
    var yearSchoolEnds = yearSchoolStarts + 1;


  //update all elements tagged with class 'YearSchoolStarts'
  $(".yearSchoolStarts").text(yearSchoolStarts);

  //update all elements tagged with class 'YearSchoolStarts'
  $(".yearSchoolEnds").text(yearSchoolEnds);

  //update last working day in February
  $(".lastWorkingDateInFebruary").text(LastWorkingDateInFebruary(yearSchoolStarts));


}

LastWorkingDateInFebruary = function(year){

    // determine last working day in February
    // start with March 1
    var lastWorkingDayInFebruary = new Date(year,2,1);
    // go to end of February (handles leap years)
    lastWorkingDayInFebruary.setDate(lastWorkingDayInFebruary.getDate()-1);
    // if a weekend day, go to previous Friday
    if(lastWorkingDayInFebruary.getDay()==0) // a Sunday
    {
         lastWorkingDayInFebruary.setDate(lastWorkingDayInFebruary.getDate()-2);
    }
    else
    {
        if(lastWorkingDayInFebruary.getDay()==6) // a Saturday
        {
             lastWorkingDayInFebruary.setDate(lastWorkingDayInFebruary.getDate()-1);
        }
    }
    //
    var lastWorkingDateInFebruary = "February " + lastWorkingDayInFebruary.getDate().toString() + ", " + year;

    return lastWorkingDateInFebruary;
}


})// end of ready function
