  /**
   * 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 boxews 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;
  };
