function Calendar(d,callBack) {
   this.startDate = 2000;
   this.endDate = 2015; //(new Date()).getFullYear();
   this.setDate(d);
   this.callBack = callBack || null;
};

Calendar.prototype = new ObjectEvents();
Calendar.prototype.setDate = function(d)
{
   d = d.split('/');
   if (parseInt(d[2]) < 30) d[2] = 2000+parseInt(d[2]);
   d = d.join('/');
   if (d) d = new Date(d);
   if (!d || isNaN(d))
      d = new Date();
   this.date = d.getDate();
   this.month = d.getMonth();
   this.year = d.getFullYear();
};

Calendar.prototype.monthNames = ['January', 'February', 'March', 'April',
				 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];


Calendar.prototype.dayNames = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];

Calendar.prototype.daysInMonth = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
				  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]];

Calendar.prototype.init = function ()
{
  var calHolder = make_el('TABLE', {className:'mini-calendar'});
  var calHeader = make_el('THEAD', calHolder);
  var calBody = make_el('TBODY', calHolder);

  this.calId = getId(calHolder);
  this.daysId = getId(calBody);

  this.buildYears(calHeader);
  this.buildMonths(calHeader);
  this.generateDays(calBody);

  this.addEvent(calHolder, 'click', 'processClick');

  return calHolder;
};

Calendar.prototype.buildDropDownHolder = function (name, where)
{
   var btn = make_el('DIV', {className:'calendar-'+name+'-minus'}, '<', where);
   btn[name+'Offset'] = -1;
   btn = make_el('DIV', {className:'calendar-'+name+'-plus'}, '>', where);
   btn[name+'Offset'] = 1;
   return make_el('DIV', {className: 'calendar-'+name+'s dropdown' }, where);
};

Calendar.prototype.buildYears = function (where)
{
   var row = make_el('TR', where);

   var btn = make_el('TH', {className: 'calendar-year-minus'}, '<', row);
   btn.yearOffset = -1;

   var th = make_el('TH', {className: 'calendar-years', colSpan: 5}, row);
   var drop = make_el('P', {className: 'dropdown'}, th);
   var year = make_el('SPAN', {className: 'calendar-year'}, this.year, drop);
   this.yearId = getId(year);

   var ul = make_el('UL', drop);
   for (var i = this.startDate; i <= this.endDate; i++)
      make_el('LI',{yearIndx:i},i,ul);

   var btn = make_el('TH', {className: 'calendar-year-plus'}, '>', row);
   btn.yearOffset = 1;
};

Calendar.prototype.buildMonths = function (where)
{
   var row = make_el('TR', where);

   var btn = make_el('TH', {className: 'calendar-month-minus'}, '<', row);
   btn.monthOffset = -1;

   var th = make_el('TH', {className: 'calendar-months', colSpan: 5}, row);
   var drop = make_el('P', {className: 'dropdown'}, th);
   var month = make_el('SPAN', {className: 'calendar-month'}, this.monthNames[this.month], drop);
   this.monthId = getId(month);

   var ul = make_el('UL', drop);
   for (var i = 0, l = this.monthNames.length; i < l; i++)
      make_el('LI', {monthIndx:i}, this.monthNames[i], ul);;

   var btn = make_el('TH', {className: 'calendar-month-plus'}, '>', row);
   btn.monthOffset = 1;
};

Calendar.prototype.buildDays = function (where)
{
   var ul = make_el('UL', {className:'calendar-days'}, where);
   this.daysId = getId(ul);
   this.generateDays(ul);
};

Calendar.prototype.getDaysInMonth = function (year, month)
{
   var leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
   return this.daysInMonth[leap?1:0][month];
};

Calendar.prototype.getDaysInYearUpToDate = function (year, month, date)
{
   var leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
   var days = 0;
   for( var i=0; i<month; i++ )
      days += this.daysInMonth[leap?1:0][i];
   return days+date;
};

Calendar.prototype.generatePastMonthOffsetDays = function (tr)
{
   var day = new Date(), year = this.year, month = this.month;
   day.setFullYear(year, month, 1);
   day = day.getDay();

   if (day)
   {
      if (--month < 0)
      {
         month = 11;
         year--;
      }

      var daysOfLastMonth = this.getDaysInMonth(year, month);
      for (var i = daysOfLastMonth - day + 1; i <= daysOfLastMonth; i++)
         make_el('TD', {className: 'calendar-past-month-name', monthIndx:month, dateIndx:i}, /* i, */ tr);
   }
};

Calendar.prototype.generateNextMonthOffsetDays = function (tr)
{
   var day = new Date(), year = this.year, month = this.month;
   day.setFullYear(year, month, this.getDaysInMonth(year, month));
   day = 6 - day.getDay();

   if (day)
   {
      if (++month > 11)
      {
         month = 0;
         year++;
      }

      for(var i = 1; i <= day; i++)
         make_el('TD', {className: 'calendar-next-month-name', monthIndx: month, dateIndx: i}, /*i,*/ tr);
   }
};

Calendar.prototype.generateDays = function (tbody)
{
   //tbody.innerHTML = '';
   kill_children(tbody);

   var tr = make_el('TR', tbody);

   for (var i = 0, l = this.dayNames.length; i < l; i++)
      make_el('TD', {className: 'calendar-day-name'}, this.dayNames[i], tr);

   var day = new Date(), year = this.year, month = this.month;
   day.setFullYear(year, month, 1);
   day = day.getDay();

   var tr = make_el('TR', tbody);
   this.generatePastMonthOffsetDays(tr);

   var daysOfMonth = this.getDaysInMonth(this.year, this.month);

   for (i = 1; i <= daysOfMonth; i++, day++)
   {
      if (i == this.date)
         make_el('TD', {dateIndx: i, className: 'calendar-current-day'}, i, tr);
      else
         make_el('TD', {dateIndx: i}, i, tr);

      if (day % 7 == 6 && i < daysOfMonth)
         tr = make_el('TR', tbody);
   }

   this.generateNextMonthOffsetDays(tr);
};

Calendar.prototype.refresh = function () {
   this.updateDays();
   this.updateMonth();
   this.updateYear();
};

Calendar.prototype.updateDays = function () {
   this.generateDays(get_by_id(this.daysId));
};

Calendar.prototype.updateMonth = function () {
   get_by_id(this.monthId).innerHTML = this.monthNames[this.month];
};

Calendar.prototype.updateYear = function () {
   get_by_id(this.yearId).innerHTML = this.year;
};

Calendar.prototype.setDateByIndex = function (indx) {
   this.date = indx;
   if (this.callBack) this.callBack(this.date, this.month, this.year);
};

Calendar.prototype.setMonthByIndex = function(indx) {
  this.month = indx;
  var daysOfMonth = this.getDaysInMonth(this.year, indx);
  if( daysOfMonth < this.date )
    this.setDateByIndex(daysOfMonth);
};

Calendar.prototype.setMonthByOffset = function(offset) {
  var indx = this.month + offset;
  if( indx < 0 ) {
    indx = 11;
    this.setYearByOffset(offset); /* this will break on offset > then |-1| */
  }
  else if( indx > 11 ) {
    indx = 0;
    this.setYearByOffset(offset); /* this will break on offset > then |-1| */
  }
  this.setMonthByIndex(indx);
};

Calendar.prototype.setYearByIndex = function(indx) {
  this.year = indx;
  var daysOfMonth = this.getDaysInMonth(this.year, this.month);
  if( daysOfMonth < this.date )
    this.setDateByIndex(daysOfMonth);
};

Calendar.prototype.setYearByOffset = function(offset) {
  this.setYearByIndex(this.year + offset);
};

Calendar.prototype.processClick = function (e) {
   var srcEl = get_srcEl(e), month=this.month, year=this.year, date=this.date;

   if( typeof srcEl.monthIndx == 'number' )
    this.setMonthByIndex(srcEl.monthIndx);

   if( typeof srcEl.yearIndx == 'number' )
    this.setYearByIndex(srcEl.yearIndx);

  else if( typeof srcEl.monthOffset == 'number' )
    this.setMonthByOffset(srcEl.monthOffset);

  else if( typeof srcEl.yearOffset == 'number' )
    this.setYearByOffset(srcEl.yearOffset);

  if( typeof srcEl.dateIndx == 'number' )
    this.setDateByIndex(srcEl.dateIndx);

  if( month != this.month || year != this.year || date != this.date )
    this.refresh();
};


function NavCalendar (id, base, day, month, year)
{
   this.holderId = id;
   this.baseUrl = base;

   var me = this;
   this.calendar = new Calendar(month+'/'+day+'/'+year, function (d, m, y) { me.jump(d, m, y); });

   get_by_id(this.holderId).appendChild(this.calendar.init());
}

NavCalendar.prototype = new ObjectEvents();

NavCalendar.prototype.jump = function (d, m, y)
{
   window.location = this.baseUrl + '/calendar/view/year/' + y + '/month/' + (m+1);
}
