/*global jQuery */

/**
 * Constructor for the class used to handle the datepicker
 * @param oPD Text field used to hold the reference to the outbound calendar. Typeof jQuery Object
 * @param oD Select field which represents the outbound day of month field. Typeof jQuery Object
 * @param oMY Select field which represents the outbound month-year field. Typeof jQuery Object
 * @param iPD Text field used to hold the reference to the inbound calendar. Optional. Typeof jQuery Object
 * @param iD Select field which represents the inbound day of month field. Optional. Typeof jQuery Object
 * @param iMY Select field which represents the inbound month-year field. Optional. Typeof jQuery Object
 * @param cb Function which is called when any of the dates have been changed. Optional. Typeof Function
 * @param fD First available date. Optional. Typeof Date
 * @param lD Last available date. Optional. Typeof Date
 * @param days Indicates the number of days the inbound and outbound should be different by, 0 is the same day and the default. Typeof Integer  (Optional)
 * @param sameDayAllowed Indicates whether we allow same day calanders true is the default. Typeof Boolean  (Optional)
 */
function Calendar(oPD, oD, oMY, iPD, iD, iMY, cb, fD, lD, days, sameDayAllowed) {
    this.firstDate = (fD !== undefined && fD !== null ? fD : new Date());
    var date = new Date();
    date.setFullYear(date.getFullYear() + 1);
    this.lastDate = (lD !== undefined && lD !== null ? lD : date);
    this.outboundPseudoDate = oPD;
    this.outboundDay = oD;
    this.outboundMonthYear = oMY;
    this.inboundPseudoDate = iPD;
    this.inboundDay = iD;
    this.inboundMonthYear = iMY;
    this.dateChangeCallBack = cb;

    //Prepopulate the pseudo date fields
    this.updateOutboundPseudoDate(true);
    this.updateInboundPseudoDate(true);

    var calendar = this;
    this.days = days;
    this.sameDayAllowed = sameDayAllowed

    // Setup onChange event handlers for select boxes
    jQuery(this.outboundDay).change(function () {
        calendar.checkDates(true);
    });
    jQuery(this.outboundMonthYear).change(function () {
        calendar.checkDates(true,null,true);
    });
    jQuery(this.inboundDay).change(function () {
        calendar.checkDates(false);
    });
    jQuery(this.inboundMonthYear).change(function () {
        calendar.checkDates(false,null,true);
    });

}

/**
 * Function used to get the currently selected outbound dates from the select box.
 * The function will also move the date if it is too early/late.
 * If the date is moved, the text field holding the calendar will be updated also.
 * @return Outbound date currently selected by the select boxes. Typeof Date.
 */
Calendar.prototype.getCurrentlySelectedOutboundDates = function () {
    var monthYear = this.outboundMonthYear.selectedValues()[0].split("-");
    var date = new Date();
    date.setFullYear(monthYear[1]); //year
    date.setMonth(parseInt(monthYear[0], 10) - 1); //month
    date.setDate(this.outboundDay.selectedValues()[0]); //day of month
    if (date < this.firstDate) {
        this.updateOutbound(this.firstDate);
        this.updateOutboundPseudoDate();
        return this.firstDate;
    } else if (date > this.lastDate) {
        this.updateOutbound(this.lastDate);
        this.updateOutboundPseudoDate();
        return this.lastDate
    }
    return date;
};

/**
 * Function used to get the currently selected inbound dates from the select box.
 * The function will also move the date if it is too early/late.
 * If the date is moved, the text field holding the calendar will be updated also.
 * @return Date currently selected by the select boxes. Typeof Date.
 */
Calendar.prototype.getCurrentlySelectedInboundDates = function () {

    var monthYear = this.inboundMonthYear.selectedValues()[0].split("-");
    var day = parseInt(this.inboundDay.selectedValues()[0], 10);
    var date = new Date();
    var year = monthYear[1];
    var month = parseInt(monthYear[0], 10) - 1;
    date.setFullYear(year); //year
    date.setMonth(month); //month
    date.setDate(day); //day of month
//    this.normalizeDate(date, day, month, year);
    if (date < this.firstDate) {
        this.updateInbound(this.firstDate);
        this.updateInboundPseudoDate();
        return this.firstDate;
    } else if (date > this.lastDate) {
        this.updateInbound(this.lastDate);
        this.updateInboundPseudoDate();
        return this.lastDate
    }
    return date;
};

/**
 * Repopulates the text field holding the outbound calendar with dates from the select boxes
 * If the date was invalid (e.g. 31st Feburary), the select fields will be updated aswell.
 * @return The date repopulated to the text field. Typeof Date.
 */
Calendar.prototype.updateOutboundPseudoDate = function (ismonth) {
    var monthYear = this.outboundMonthYear.selectedValues()[0].split("-");
    var day = parseInt(this.outboundDay.selectedValues()[0], 10);
    var date = new Date();
    var year = monthYear[1];
    var month = parseInt(monthYear[0], 10) - 1;
    date.setFullYear(year); //year
    date.setDate(day); //day of month
    date.setMonth(month); //month
    date.setDate(day); //day of month
    if(ismonth !== undefined && ismonth !== null && ismonth == true) {
        this.normalizeDate(date, day, month, year, true);
    }
    this.outboundPseudoDate.val(jQuery.datepicker.formatDate("yy-mm-dd", date));
    if (ismonth !== undefined && ismonth !== null && ismonth == true && date.getDate() !== day) {
        this.updateOutbound(date);
    }
    return date;
};

Calendar.prototype.normalizeDate = function (date, day, month, year, outbound) {
    var aDayInMillis = 1000 * 60 * 60 * 24;
    while(date.getMonth() > month)
    {
        date.setTime(date.getTime() - aDayInMillis);
    }

    var today = new Date();
    if(today.getTime() > date.getTime())
    {
        var isSameDay =  ((this.sameDayAllowed !== undefined && this.sameDayAllowed !== null) ? this.sameDayAllowed : true)
        var milliseconds = ((this.days !== undefined && this.days !== null) ? this.days : 0) * 1000 * 60 * 60 * 24;
        if(isSameDay || outbound) {
            date.setTime(today.getTime() + aDayInMillis);
        } else {
            date.setTime(today.getTime() + aDayInMillis + milliseconds);
        }
    }
}

/**
 * Repopulates the text field holding the inbound calendar with dates from the select boxes
 * If the date was invalid (e.g. 31st Feburary), the select fields will be updated aswell.
 * @return The date repopulated to the text field. Typeof Date.
 */
Calendar.prototype.updateInboundPseudoDate = function (ismonth) {
    if (this.inboundPseudoDate !== undefined && this.inboundPseudoDate !== null) {

    var monthYear = this.inboundMonthYear.selectedValues()[0].split("-");
    var day = parseInt(this.inboundDay.selectedValues()[0], 10);
    var date = new Date();
    var year = monthYear[1];
    var month = parseInt(monthYear[0], 10) - 1;
    date.setFullYear(year); //year   
    date.setDate(day); //day of month
    date.setMonth(month); //month
    date.setDate(day); //day of month
    if(ismonth !== undefined && ismonth !== null && ismonth == true) {
        this.normalizeDate(date, day, month, year, true);
    }
      this.inboundPseudoDate.val(jQuery.datepicker.formatDate("yy-mm-dd", date));
      if (ismonth !== undefined && ismonth !== null && ismonth == true && date.getDate() !== day) {
          this.updateInbound(date);
      }
      return date;
    }
};

/**
 * Function called when selecting a date via the calendar.
 * Updates the select fields and then checks that the outbound/inbound combination is valid
 * @param dateText Date that the user selected. Typeof Date.
 * @param outbound Indicates whether the user selected a new outbound date or not. True for outbound, false for inbound. Typeof Boolean.
 */
Calendar.prototype.updateDates = function (dateText, outbound) {
    if (dateText !== null) {
        if (outbound) {
            this.updateOutbound(dateText);
        } else {
            this.updateInbound(dateText);
        }
        this.checkDates(outbound, true);
    }
};

/**
 * Checks whether the outbound/inbound combination is valid and updates the select boxes as needed.
 * @param outbound Indicates whether the user selected a new outbound date or not. True for outbound, false for inbound. Typeof Boolean.
 * @param automatic Incidates whether the function is being called from the user selecting a new date from the drop-down calendar or not.
 *  99% of the time this should be false (or nothing at all)
 */
Calendar.prototype.checkDates = function (outbound, automatic, month) {
    if (this.inboundPseudoDate !== undefined && this.inboundPseudoDate !== null) {
      var outboundDate, inboundDate;
      var today = new Date();
      today.setMilliseconds(0);
      today.setSeconds(0);
      today.setMinutes(0);
      today.setHours(0);
      today.setTime(today.getTime() + (1000 * 60 * 60 * 24));
      var milliseconds = ((this.days !== undefined && this.days !== null) ? this.days : 0) * 1000 * 60 * 60 * 24;
      var isSameDay =  ((this.sameDayAllowed !== undefined && this.sameDayAllowed !== null) ? this.sameDayAllowed : true)
      if (automatic === undefined || automatic === null || !automatic) {
          outboundDate = this.updateOutboundPseudoDate(month);
          inboundDate = this.updateInboundPseudoDate(month);
      } else {
          outboundDate = jQuery.datepicker.parseDate("yy-mm-dd", this.outboundPseudoDate.val());
          inboundDate = jQuery.datepicker.parseDate("yy-mm-dd", this.inboundPseudoDate.val());
      }

     if(outbound) {
          if (  outboundDate.getTime() > (inboundDate.getTime() - milliseconds)) {
                  inboundDate.setTime(outboundDate.getTime() + milliseconds);
          }
      } else if(month !== undefined && month !== null && month == true){
          if (   ( (isSameDay) && (outboundDate.getTime() > inboundDate.getTime()))
              || ((!isSameDay) && (outboundDate.getTime() > (inboundDate.getTime() - milliseconds)))) {
                  outboundDate.setTime(inboundDate.getTime() - milliseconds);
                  this.updateOutbound(outboundDate);
              }
     }
     if(month !== undefined && month !== null && month == true)
     {
          if(outboundDate.getTime() < today.getTime()) {
            outboundDate.setTime(today.getTime());
          }
          if(    ( (isSameDay) && (today.getTime() >= inboundDate.getTime()))
              || ((!isSameDay) && ((inboundDate.getTime() - milliseconds) < today.getTime()))) {
            inboundDate.setTime(today.getTime() + milliseconds);
          }

          if(inboundDate.getTime() < today.getTime())
          {
              inboundDate.setTime(today.getTime())
          }
          if(outboundDate.getTime() < today.getTime())
          {
              outboundDate.setTime(today.getTime())
          }
     }


//      this.repopulateDayDropDown(inboundDate, this.inboundDay, milliseconds, isSameDay);

     if(outbound || month !== undefined && month !== null && month == true)
     {
      this.updateInbound(inboundDate);
     }
      this.updateInboundPseudoDate(month);
//     this.repopulateDayDropDown(outboundDate, this.outboundDay, milliseconds, true);
        // (!outbound) || 
     if(month !== undefined && month !== null && month == true)
     {
      this.updateOutbound(outboundDate);
     }
      this.updateOutboundPseudoDate(month);

      if (this.dateChangeCallBack !== null && this.dateChangeCallBack !== undefined) {
          this.dateChangeCallBack();
      }

    }
};


/**
 * Updates the inbound select boxes with the new date.
 * @param date Date that the select boxes should be updated to. Typeof Date
 */
Calendar.prototype.updateInbound = function (date) {
    this.inboundMonthYear.selectOptions(jQuery.datepicker.formatDate('mm-yy', date));
    this.inboundDay.selectOptions(parseInt(jQuery.datepicker.formatDate('dd', date), 10) + "");
};

Calendar.prototype.repopulateDayDropDown = function (date, dropDown, milliseconds, isSameDay) {
    var aDayInMillis = 1000 * 60 * 60 * 24;
    var itteratorDate = new Date();
    itteratorDate.setTime(itteratorDate.getTime() + aDayInMillis);
    if(!isSameDay)
    {
         itteratorDate.setTime(itteratorDate.getTime() + milliseconds);
    }
    dropDown.removeOption(/./);

    if(date.getMonth() !== itteratorDate.getMonth() || date.getFullYear() !== itteratorDate.getFullYear()) {
        itteratorDate.setFullYear(date.getFullYear());
        itteratorDate.setMonth(date.getMonth());
        itteratorDate.setDate(1);
    }
    while(date.getMonth() === itteratorDate.getMonth()){
       var text = parseInt(jQuery.datepicker.formatDate('dd', itteratorDate), 10) + "";
       dropDown.addOption(text,text);
       itteratorDate.setTime(itteratorDate.getTime() + aDayInMillis);
    }
}

/**
 * Updates the outbound select boxes with the new date.
 * @param date Date that the select boxes should be updated to. Typeof Date
 */
Calendar.prototype.updateOutbound = function (date) {
    this.outboundMonthYear.selectOptions(jQuery.datepicker.formatDate('mm-yy', date));
    this.outboundDay.selectOptions(parseInt(jQuery.datepicker.formatDate('dd', date), 10) + "");
};

/**
 * Gets the element that holds the reference to the outbound datepicker
 * @return Typeof jQuery element.
 */
Calendar.prototype.getOutbound = function () {
    return this.outboundPseudoDate;
};

/**
 * Gets the element that holds the reference to the inbound datepicker
 * @return Typeof jQuery element.
 */
Calendar.prototype.getInbound = function () {
    return this.inboundPseudoDate;
};

/**
 * Gets the first available date.
 * @return Typeof Date.
 */
Calendar.prototype.getFirstDate = function () {
    return this.firstDate;
};

/**
 * Sets the first date that the user should be able to select
 * @param date Typeof Date.
 */
Calendar.prototype.setFirstDate = function (date) {
    this.firstDate = date;
};

/**
 * Gets the last available date.
 * @return Typeof Date.
 */
Calendar.prototype.getLastDate = function () {
    return this.lastDate;
};

/**
 * Sets the last date that the user should be able to select
 * @param date Typeof Date.
 */
Calendar.prototype.setLastDate = function (date) {
    this.lastDate = date;
};

/**
 * Gets the text field that holds the reference to the outbound calendar
 * @return Typeof jQuery element.
 */
Calendar.prototype.getOutboundPseudoDate = function () {
    return this.outboundPseudoDate;
};

/**
 * Sets the text field that holds the reference to the outbound calendar
 * @param element Typeof jQuery element.
 */
Calendar.prototype.setOutboundPseudoDate = function (element) {
    this.outboundPseudoDate = element;
};

/**
 * Gets the select field that is used by the user to select the day of the month for the outbound flight
 * @return Typeof jQuery element.
 */
Calendar.prototype.getOutboundDay = function () {
    return this.outboundDay;
};

/**
 * Sets the select field which is used by the user to select the day of the month for the outbound flight
 * @param element jQuery element
 */
Calendar.prototype.setOutboundDay = function (element) {
    this.outboundDay = element;
};

/**
 * Gets the select field that is used by the user to select the month-year combination for the outbound flight
 * @return Typeof jQuery element.
 */
Calendar.prototype.getOutboundMonthYear = function () {
    return this.outboundMonthYear;
};

/**
 * Sets the select field which is used by the user to select the month-year combination for the outbound flight
 * @param element Typeof jQuery element.
 */
Calendar.prototype.setOutboundMonthYear = function (element) {
    this.outboundMonthYear = element;
};

/**
 * Gets the text field that holds the reference to the inbound calendar
 * @return Typeof jQuery element.
 */
Calendar.prototype.getInboundPseudoDate = function () {
    return this.inboundPseudoDate;
};

/**
 * Sets the text field that holds the reference to the inbound calendar
 * @param element Typeof jQuery element.
 */
Calendar.prototype.setInboundPseudoDate = function (element) {
    this.inboundPseudoDate = element;
};

/**
 * Gets the select field that is used by the user to select the day of the month for the inbound flight
 * @return Typeof jQuery element.
 */
Calendar.prototype.getInboundDay = function () {
    return this.inboundDay;
};

/**
 * Sets the select field which is used by the user to select the day of the month for the inbound flight
 * @param element jQuery element
 */
Calendar.prototype.setInboundDay = function (element) {
    this.inboundDay = element;
};

/**
 * Gets the select field that is used by the user to select the month-year combination for the inbound flight
 * @return Typeof jQuery element.
 */
Calendar.prototype.getInboundMonthYear = function () {
    return this.inboundMonthYear;
};

/**
 * Sets the select field which is used by the user to select the month-year combination for the outbound flight
 * @param element Typeof jQuery element.
 */
Calendar.prototype.setInboundMonthYear = function (element) {
    this.inboundMonthYear = element;
};
