// ***************************************************************************
// This is a heavily modified version of a datepicker by Mathieu Jondet
// which contained the heading:
//
// // DatePicker widget using Prototype and Scriptaculous.
// //(c) 2007 Mathieu Jondet <mathieu@eulerian.com>
// // Eulerian Technologies
//
// // DatePicker is freely distributable under the same terms as Prototype.
//
// Copyright 2007 Starscale Inc.
// end rights

// ibi.DatePicker setup
//
// The date picker must be fairly strictly constructed to work properly.
//
// - There must be a main div in which the date dropdowns and the link to
// show the calendar div will live.  You can name this div whatever you like
// (for the next few minutes, we'll call it {mainDiv}
// - The link element that launches the calendar must have an id of
// "{mainDiv}Link".  The calendar div is place relative to this element.
// - The year, month and day drop downs must be named "{mainDiv}Year",
// "{mainDiv}Month", and "{mainDiv}Day" respectively
//
// Example:
//
//
//    <div id="mydatepicker" style="border: 1px solid red;">
//
//
//      <select id="mydatepickerDay"><t:text/></select>
//        
//        <select id="mydatepickerMonth">
//        </select>
//        
//        <select id="mydatepickerYear">
//        </select>      
//      
//      <a href="" id="mydatepickerLink">open cal</a>
//    </div>
//    
//    <script>
//      new ibi.DatePicker({mainDiv: 'mydatepicker',
//      growDirection: 'top-right', top: -5, left: -105, day: 25, month: 8,
//      year: 2005});
//    </script>
//
//

// ibi.DatePicker Options
//
// The following options can be passed in to the SSDatepicker class in the
// options hash.
//
// - mainDiv: the name of the div that the dropdowns and link to show the
// calendar reside.  This is also the prefix of the key inner elements
// - top: the vertical offset from the link div position to move the calendar
// div.  This can be negative or positive and the default is .0
// - left: the horizontal offset from the link div position to move the
// calendar div.  This can be negative or positive and the default is 0.
// - growDirection: the direction the Grow/Shrink effects work from.  See
// for further details.
// - day: the day to set the calendar and day dropdown to. Defaults to current
// day
// - month: the number of the month (1-12) to set the calendar and month
// dropdown to. Defaults to current month
// - year: the year to set the calendar and year dropdown to. Defaults to this
// year.
// - selectDate: if true, the year, month and day dropdowns will be set to the
// date specified (either today or the date specified by the day, month, year
// parameters). If false, the values 'Year', 'Mon', 'Day' will be selected in
// the dropdowns. Defaults to true.
// - changeCallback: a function to call when a date is selected

// Without further ado:

ibi.DatePicker = Class.create({
 CVersion: '1.1',
  _mainDiv : 'ssdatepicker',
  _linkEl : null, 
  _topOffset : 0, 
  _leftOffset : 0, 
  _yearsBack : 100, 
  _growDirection : 'top-left',
  _todayDate	: new Date(),
  _selectDate : true, 
  // Date data
  _daysInMonth	: [31,28,31,30,31,30,31,31,30,31,30,31],
  _months : [ 'January', 'February', 'March', 'April', 'May',
              'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
  _days :  [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],

  /**
   * Initialize the date picker
   */
  initialize	: function ( h_p ) {
    
    // parameters
    this._mainDiv = h_p["mainDiv"] || this._mainDiv;
    this._selectDate = h_p["selectDate"] || this._selectDate;
    this._topOffset = h_p["top"] || this._topOffset;
    this._leftOffset = h_p["left"] || this._leftOffset;
    this._growDirection = h_p["growDirection"] || this._growDirection;
    this._calendar_id = this._mainDiv + 'Calendar';
    this._callback = h_p["changeCallback"] || Prototype.emptyFunction;
    
    // initialize the date
    var now = new Date();
    this._current_day = h_p["day"] || now.getDate();
    if (h_p["month"]) {
      this._current_month = h_p["month"] - 1;
    } else {
      this._current_month = now.getMonth();
    }
    this._current_year = h_p["year"] || now.getFullYear();

    //    console.log(this._current_day + "/" + this._current_month + "/" + this._current_year);
    
    // Initialize div ids
    this._yearDivId = this._mainDiv + "Year";
    this._monthDivId = this._mainDiv + "Month";
    this._dayDivId = this._mainDiv + "Day";
    
    // Init the divs
    this._fillDateSelects();
    this._buildCalendarDiv();

    // Set the link onClick
    var _self = this;
    this._linkEl = this._mainDiv+'Link';
    $(this._linkEl).onclick = function () { _self.click(); return false; };
  },
  
  /**
   * Fill the date dropdowns
   *
   */
  _fillDateSelects : function () {

    // Day
    var el = $(this._dayDivId);
    el.appendChild(this._createOption("Day"));
    for (var i = 1; i <= 31; i++) {
      el.appendChild(this._createOption(i));
    }

    // Month
    var el = $(this._monthDivId);
    el.appendChild(this._createOption("Mon"));      
    this._fillMonthSelect(el);

    var el = $(this._yearDivId);
    el.appendChild(this._createOption("Year"));
    this._fillYearSelect(el, this._yearDivId);

    if (this._selectDate == true) {
      $(this._monthDivId).selectedIndex = this._current_month + 1;
      $(this._dayDivId).selectedIndex = this._current_day;
      $(this._yearDivId).down("option#"+ this._yearDivId + this._current_year).selected = true;
    }

  },

  /**
   * Fill the given select element with the months 
   */
  _fillMonthSelect: function(select) {
    for (var i = 0; i < 12; i++) {
      var opt = this._createOption(this._months[i].substr(0, 3));
      opt.value = i + 1;
      select.appendChild(opt);
    }
  },

  /**
   * Fill the given select element with the years from the current
   * year back this._yearsBack years
   */ 
  _fillYearSelect : function(select, idprefix) {
    var year = (new Date()).getFullYear();    
    for (var i = year; i >= year - this._yearsBack; i--) {
      var opt = this._createOption(i);
      opt.id = idprefix+i;
      opt.value = i;
      select.appendChild(opt);
    }
  },

  /**
   * Create an option element
   */
  _createOption : function(text) {
    var option = document.createElement('option');
    option.innerHTML = text;
    return option;
  },
  
  /**
   * Build the calendar div so we can later put the date selection in
   *
   */
  _buildCalendarDiv : function () {

    var _self = this;
    /* build up calendar skel */
    var div = document.createElement('div');
    div.setAttribute('id', this._calendar_id);
    div.style.display = 'none';
    /* in case we have overlapping datepickers */
    div.style.zindex = this._zindex;	
    div.className = 'datepicker';
    /* div for header */
    var divHdr	= document.createElement('div');
    divHdr.className = 'datepicker-header';
    
    var spanHdr	= document.createElement('span');
    spanHdr.setAttribute('id', this._calendar_id+'-header');
    divHdr.appendChild( spanHdr );

    var monthSelect = document.createElement('select');
    monthSelect.setAttribute('class', 'datepicker-header-select');
    monthSelect.setAttribute('id', _self._calendar_id + "Month");
    monthSelect.onchange = function() { _self.updateCalendar(); }
    _self._fillMonthSelect(monthSelect);
    monthSelect.selectedIndex = _self._current_month;
    spanHdr.appendChild(monthSelect);

    
    var yearSelect = document.createElement('select');
    var yearId = _self._calendar_id + "Year";
    
    yearSelect.setAttribute('class', 'datepicker-header-select');
    yearSelect.setAttribute('id', yearId);
    yearSelect.onchange = function() { _self.updateCalendar(); }    
    _self._fillYearSelect(yearSelect, yearId);
    //    $(yearId).down("option#" + yearId + _self._current_year).selected = true;    
    
    spanHdr.appendChild(yearSelect);    
    
    div.appendChild( divHdr );
    
    /* div for calendar information */
    var divCal	= document.createElement('div');
    divCal.className	= 'datepicker-calendar';
    var tableCal	= document.createElement('table');
    tableCal.setAttribute('id', this._calendar_id+'-table');
    /* append everything to main div */
    divCal.appendChild( tableCal );
    div.appendChild( divCal );

     
    
    /* generate footer */
    var divFtr	= document.createElement('div');
    divFtr.className = 'datepicker-footer';
    divFtr.onclick= function () { _self.close(); }
    divFtr.innerHTML = "Close";
    div.appendChild( divFtr );
    this._div	= div;
    
    /* need to append on body when doc is loaded for IE */
    Event.observe(window, 'load', this.load.bindAsEventListener(this), false);
    
  },


  /**
   * load	: called when document is fully-loaded to append datepicker
   *		  to main object.
   *
   */
  load		: function () {

    /* append to body */
    var body = document.getElementsByTagName('body').item(0);
    if ( body ) {
      body.appendChild( this._div );
      this._redrawCalendar();      
      /* position the datepicker relatively to element */
      var a_lt = Position.cumulativeOffset($(this._linkEl));

      $(this._calendar_id).style.left = (Number(a_lt[0])+ Number(this._leftOffset)) + 'px';
      $(this._calendar_id).style.top = (Number(a_lt[1]) + Number(this._topOffset))+'px';
    }
  },  


  /**
   * close	: called when the datepicker is closed
   *
   */
  close		: function () {
    new Effect.Shrink(this._calendar_id, {duration: 1, direction: this._growDirection});

  },
    
  
  /**
   * _getMonthDays : given the year and month find the number of days.
   *
   */
  _getMonthDays	: function ( year, month ) {
    if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && 
        (month == 1)) {
          return 29;
        } else {
          return this._daysInMonth[month];
        }
  },
  
  /**
   * _buildCalendar	: draw the days array for current date
   *
   */
  _buildCalendar		: function () {
    var _self	= this;
    var tbody	= document.createElement('tbody');
    /* generate day headers */
    var trDay	= document.createElement('tr');
    this._days.each( function ( item ) {
      var td	= document.createElement('td');
      td.innerHTML	= item;
      td.className	= 'wday';
      trDay.appendChild( td );
    });
    tbody.appendChild( trDay );
    /* generate the content of days */
    
    /* build-up days matrix */
    var a_d	= [
                   [ 0, 0, 0, 0, 0, 0, 0 ]
                   ,[ 0, 0, 0, 0, 0, 0, 0 ]
                   ,[ 0, 0, 0, 0, 0, 0, 0 ]
                   ,[ 0, 0, 0, 0, 0, 0, 0 ]
                   ,[ 0, 0, 0, 0, 0, 0, 0 ]
                   ,[ 0, 0, 0, 0, 0, 0, 0 ]
    ];
    /* set date at beginning of month to display */
    var d		= new Date(this._current_year, this._current_month, 1, 12);
    /* start the day list on sunday */
    var startIndex	= d.getDay();
    var nbDaysInMonth	= this._getMonthDays(
                                             this._current_year, this._current_month);
    var daysIndex		= 1;
    for ( var j = startIndex; j < 7; j++ ) {
      a_d[0][j]	= { 
        d : daysIndex
        ,m : this._current_month
        ,y : this._current_year 
      };
      daysIndex++;
    }
    var a_prevMY	= this._prevMonthYear();
    var nbDaysInMonthPrev	= this._getMonthDays(a_prevMY[1], a_prevMY[0]);
    for ( var j = 0; j < startIndex; j++ ) {
      a_d[0][j]	= { 
        d : Number(nbDaysInMonthPrev - startIndex + j + 1) 
        ,m : Number(a_prevMY[0])
        ,y : a_prevMY[1]
        ,c : 'outbound'
      };
    }
    var switchNextMonth	= false;
    var currentMonth	= this._current_month;
    var currentYear	= this._current_year;
    for ( var i = 1; i < 6; i++ ) {
      for ( var j = 0; j < 7; j++ ) {
        a_d[i][j]	= { 
          d : daysIndex
          ,m : currentMonth
          ,y : currentYear
          ,c : ( switchNextMonth ) ? 'outbound' : ( 
                                                   ((daysIndex == this._todayDate.getDate()) &&
                                                    (this._current_month  == this._todayDate.getMonth()) &&
                                                    (this._current_year == this._todayDate.getFullYear())) ? 'today' : null)
        };
        daysIndex++;
        /* if at the end of the month : reset counter */
        if ( daysIndex > nbDaysInMonth ) {
          daysIndex	= 1;
          switchNextMonth = true;
          if ( this._current_month + 1 > 11 ) {
            currentMonth = 0;
            currentYear += 1;
          } else {
            currentMonth += 1;
          }
        }
      }
    }
    
    /* generate days for current date */
    for ( var i = 0; i < 6; i++ ) {
      var tr	= document.createElement('tr');
      for ( var j = 0; j < 7; j++ ) {
        var h_ij	= a_d[i][j];
        var td	= document.createElement('td');
        var id	= $A([ this._mainDiv, (h_ij["m"] +1),
                       h_ij["d"], h_ij["y"] ]).join('-');
        
        /* set id and classname for cell if exists */
        td.setAttribute('id', id);
        if ( h_ij["c"] )
          td.className	= h_ij["c"];
        /* on onclick : rebuild date value from id of current cell */
        td.onclick	= function () {

          var parts = this.id.replace(_self._mainDiv+'-','').split("-");
          $(_self._monthDivId).selectedIndex = parts[0];
          $(_self._dayDivId).selectedIndex = parts[1];
          $(_self._yearDivId).down("option#"+_self._yearDivId + parts[2]).selected = true;
          
          // call the callback
          _self._callback();
          
          _self.close(); 
        };
        td.innerHTML= h_ij["d"];
        tr.appendChild( td );
      }
      tbody.appendChild( tr );
    }
    return	tbody;
  },
  
  /**
   * updateCalendar: take the values of the calendar drop downs
   *                 and redraw the calendar
   *
   */
  updateCalendar: function () {
    var monthEl = $(this._calendar_id+"Month");
    this._current_month  = monthEl.selectedIndex;
    var yearEl = $(this._calendar_id+"Year");
    this._current_year = yearEl.options[yearEl.selectedIndex].value
    this._redrawCalendar();
  },

  _nextMonthYear	: function () {
    var c_mon	= this._current_month;
    var c_year	= this._current_year;
    if ( c_mon + 1 > 11 ) {
      c_mon	= 0;
      c_year	+= 1;
    } else {
      c_mon     += 1;
    }
    return	[ c_mon, c_year ];
  },


  _prevMonthYear	: function () {
    var c_mon	= this._current_month;
    var c_year	= this._current_year;
    if ( c_mon - 1 < 0 ) {
      c_mon	= 11;
      c_year	-= 1;
    } else {
      c_mon	-= 1;
    }
    return	[ c_mon, c_year ];
  },  


  /**
   * Redraw the calendar
   */
  _redrawCalendar	: function () {
    
    var table	= $(this._calendar_id+'-table');
    try {
      while ( table.hasChildNodes() )
        table.removeChild(table.childNodes[0]);
    } catch ( e ) {}
    table.appendChild( this._buildCalendar() );
  },

  /**
   * click	: called when input element is clicked
   *
   */
  click	: function () {
    new Effect.Grow(this._calendar_id, {duration: 1, direction: this._growDirection});

  }

});


