/*
  -------------------------------------------------------------------------------------------------

  : calendar.js
  : ben miller : ben@hyl.co.uk : http://digital.hyl.co.uk

  : many thanks to Matt Kruse <http://www.mattkruse.com> for the disabled dates idea.

  : requires
  : hyl_client/1_0/frame.js

  -------------------------------------------------------------------------------------------------
*/
var hyl = hyl || {};
hyl.resourcePath = hyl.resourcePath || '/hyl_client/1_0/';

var __hylCalendar = [];

AEL(window, 'load', function() { for(var i=0;i<__hylCalendar.length;i++) { __hylCalendar[i].load(); } }, false);
AEL(document, 'click', function() { for(var i=0;i<__hylCalendar.length;i++) { __hylCalendar[i].hide(); } }, false);

/*
  Calendar
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar = function(_doc, _id)
{
  if(arguments.length>0)
  {
    _doc = _doc || document;
    this.init(_doc, _id);
  }
}

hyl.Calendar.prototype = new hyl.Frame;

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.DayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
hyl.Calendar.MonthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.init = function(_doc, _id)
{
  hyl.Frame.call(this, _doc, _id);

  this.index = __hylCalendar.length;
  __hylCalendar.push(this);

  this.id                 = _id;
  this._date              = new Date(); // running date
  this.selectedDate       = null; // selected date
  this.selectHandler      = []; // functions to be called when a date is selected
  this.weekStartDay       = 0; // day week starts on
  this.disabledDatesExpr  = ''; // disabled dates expression

  this.CSS                = '@import "' + hyl.resourcePath + 'calendar.css";';
  this.relPos             = 'btrr';
  this.draggable          = true;
  this.frm.style.width    = '150px';
  this.frm.style.height   = '150px';
  this.frm.style.position = 'absolute';
  this.frm.frameBorder    = 0;
  this.frm.scrollbars     = false;

  this.dayNames           = hyl.Calendar.DayNames;
  this.monthNames         = hyl.Calendar.MonthNames;
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.load = function()
{
  hyl.Frame.prototype.load.call(this);
  this.update();
  this.hide();
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.update = function(d)
{
  this._date = d || this.selectedDate || this._date;
  this.build();
  hyl.Frame.prototype.update.call(this);
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.build = function()
{
  var dCal  = new Date(this._date.getFullYear(), this._date.getMonth(), 1);
  var dPrev = new Date(this._date.getFullYear(), this._date.getMonth()-1, 1);
  var dNext = new Date(this._date.getFullYear(), this._date.getMonth()+1, 1);

  // week day offset
  dCal.setDate(this.weekStartDay - dCal.getDay() + 1);

  var rtn = [];
  rtn.push('<scr', 'ipt type="text/javascript">__hylCalendar = parent.__hylCalendar[', this.index, '];</script>');

  // head
  rtn.push('<div id="head">');
  rtn.push('<span id="prevMonth" title="', this.monthNames[dPrev.getMonth()], '" onclick="__hylCalendar.update(new Date(', dPrev.getTime(), '));">&lt;&lt;</span>');
  rtn.push('<p id="title">', this.monthNames[this._date.getMonth()].substr(0, 3), ' ', this._date.getFullYear(), '</p>');
  rtn.push('<span id="nextMonth" title="', this.monthNames[dNext.getMonth()], '" onclick="__hylCalendar.update(new Date(', dNext.getTime(), '));">&gt;&gt;</span>');
  rtn.push('</div>');

  // calendar start
  rtn.push('<table cellpadding="0" cellspacing="0">');

  // day names
  rtn.push('<tr>');
  for(var i=0; i<7; i++)
  {
    var dayName = this.dayNames[(this.weekStartDay+i)%7];
    rtn.push('<th title="', dayName, '">', dayName.substr(0,1), '</th>');
  }
  rtn.push('</tr>');

  // days
  for(var row=0; row<6; row++)
  {
    rtn.push('<tr>');

    for(var col=0; col<7; col++)
    {
      var tdClass = '';

      if(dCal.getDay() == 0 || dCal.getDay() == 6)
      {
        tdClass += ' weekend';
      }

      if(this.selectedDate && dCal.getFullYear() == this.selectedDate.getFullYear() && dCal.getMonth() == this.selectedDate.getMonth() && dCal.getDate() == this.selectedDate.getDate())
      {
        tdClass += ' selected';
      }

      if(dCal.getMonth() != this._date.getMonth())
      {
        tdClass += ' notInMonth';
      }

      if(this.isDisabledDate(dCal))
      {
        rtn.push('<td class="', tdClass, ' disabled">', dCal.getDate(), '</td>');
      }
      else
      {
        rtn.push('<td class="', tdClass, '" onclick="__hylCalendar.select(new Date(', dCal.getTime(), '));">');
        rtn.push(dCal.getDate(), '</td>');
      }

      dCal.setDate(dCal.getDate() + 1);
    }

    if(dCal.getMonth() > this._date.getMonth() || dCal.getFullYear() > this._date.getFullYear()) { break; }

    rtn.push('</tr>');
  }

  rtn.push('</table>');

  // foot
  var dToday = new Date();
  if(!this.isDisabledDate(dToday))
  {
    rtn.push('<div id="foot" onclick="__hylCalendar.select(new Date(', dToday.getTime(), '));" ');
    rtn.push('title="', dToday.getDate() + ' ' + this.monthNames[dToday.getMonth()] + ' ' + dToday.getFullYear(), '">today</div>');
  }

  this.content = rtn.join('');
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.hide = function()
{
  this.frm.style.display = 'none';
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.show = function()
{
  this.frm.style.display = 'block';
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.toggleDisplay = function(e)
{
  CBUB(e);
  if(this.frm.style.display == 'none')
  {
    this.update();
    this.show();

    if(!this.hasPosition)
    {
      this.position(hyl.srcEl(e));
      this.hasPosition = true;
    }

    if(this.draggable)
    {
      this.addDrag(this.doc().getElementById('title'));
    }
  }
  else
  {
    this.hide();
  }
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.select = function(d)
{
  this.selectedDate = d;
  for(var i=0; i<this.selectHandler.length; i++)
  {
    this.selectHandler[i]();
  }
  this.hide()
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.setDisabledDate = function(dStart, dEnd)
{
  if(!IS.D(dStart) && !IS.D(dEnd)) { return; }

  if(arguments.length == 1) { dEnd = dStart; }

  if(this.disabledDatesExpr != '') { this.disabledDatesExpr += '||'; }

  if(dStart == null)
  {
    this.disabledDatesExpr += '(ds<='+ dEnd.getTime() +')';
  }
  else if(dEnd == null)
  {
    this.disabledDatesExpr += '(ds>='+ dStart.getTime() +')';
  }
  else
  {
    this.disabledDatesExpr += '(ds>='+ dStart.getTime() +'&&ds<='+ dEnd.getTime() +')';
  }
}

/*
  -------------------------------------------------------------------------------------------------
*/
hyl.Calendar.prototype.isDisabledDate = function(d)
{
  if(this.disabledDatesExpr != '')
  {
    var ds = d.getTime();
    return eval('('+ this.disabledDatesExpr +')');
  }
  return false;
}

