/*-------------- Calendar Class --------------*/

var JiveCalendar = Class.create();

/*-------------- Calendar Variables --------------*/
JiveCalendar._DIM = new Array(null, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
/*-------------- End Calendar Variables ----------*/

JiveCalendar.prototype = {

  initialize: function(year, month, day, hour, minute, second) {
	if (year == null) {
		this.date = new Date();
	} else if(second != null) {
		this.date = new Date(year, month - 1, day, hour, minute, second);
	} else if(minute != null) {
		this.date = new Date(year, month - 1, day, hour, minute);
	} else if(hour != null){
		this.date = new Date(year, month - 1, day, hour);
	} else if(day != null) {
		this.date = new Date(year, month - 1, day);
	} else if(month != null) {
		this.date = new Date(year, month - 1);
	} else if(year != null) {
		this.date = new Date(year);
	}
  },

  getDate: function() {
	return this.date;
  },

  setDate: function(date) {
	this.date = date;
  },

  getDayOfMonth: function() {
	return this.date.getDate();
  },

  getDayOfWeek: function() {
	return this.date.getDay();
  },

  getMonth: function() {
	return this.date.getMonth() + 1;
  },

  getYear: function() {
	return this.date.getFullYear();
  },

  getDayName: function(wday) {
	if (wday == null) wday = this.getDayOfWeek();
	return JiveCalendar._DN[wday];
  },

  getAbbrDayName: function(wday) {
	if (wday == null) wday = this.getDayOfWeek();
	return JiveCalendar._SDN[wday];
  },

  getMonthName: function(month) {
	if (month == null) month = this.getMonth();
	return JiveCalendar._MN[month];
  },

  getAbbrMonthName: function(month) {
	if (month == null) month = this.getMonth();
	return JiveCalendar._SMN[month];
  },

  getDaysInMonth: function(year, month) {
	if (year == null) year = this.getYear();
	if (month == null) month = this.getMonth();
	if (this.isLeap(year)) {
		JiveCalendar._DIM[2] = 29;
	} else {
		JiveCalendar._DIM[2] = 28;
	}
	return JiveCalendar._DIM[month]
  },

  getFirstDayOfMonth: function(year, month) {
	  if (year == null) year = this.getYear();
	if (month == null) month = this.getMonth();
	var date = new Date(year, month - 1, 1);
	return date.getDay();
  },

  isLeap: function(year) {
	  if (year == null) year = this.getYear();
	  if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
		  return true;
	  }
	  return false;
  },

  getCurrentMonth: function() {
	  return new JiveCalendar();
  },

  getPrevMonth: function() {
	  var m = this.getMonth();
	  var y = this.getYear();
	  if(m == 1) {
		m  = 12;
		y -= 1;
	  } else {
		m -= 1;
	  }
	  return new JiveCalendar(y, m);
  },

  getNextMonth: function() {
	  var m = this.getMonth();
	  var y = this.getYear();
	  if(m == 12) {
		m = 1;
		y += 1;
	  } else {
		m += 1;
	  }
	  return new JiveCalendar(y, m);
  },

  getYesterday: function() {
	  var d = this.getDayOfMonth();
	  var m = this.getMonth();
	  var y = this.getYear();
	  if(d == 1) {
		  pm = this.getPrevMonth();
		  d = pm.getDaysInMonth();
		  m = pm.getMonth();
		  y = pm.getYear();
	  } else {
		  d -= 1;
	  }
	  return new JiveCalendar(y, m, d);
  },

  getTomorrow: function() {
	  var d = this.getDayOfMonth();
	  var m = this.getMonth();
	  var y = this.getYear();
	  var dim = this.getDaysInMonth();
	  if(d == dim) {
		  nm = this.getNextMonth();
		  d = 1;
		  m = nm.getMonth();
		  y = nm.getYear();
	  } else {
		  d += 1;
	  }
	  return new JiveCalendar(y, m, d);
  }

}


/*-------------- Calendar Helpers --------------*/

/**
 * This is a basic Helper that prints a Tabled Calendar within a specified element.
 *
 * @param   element    Id of the element
 * @param   calendar   Calendar Object
 * @param   goals	   A map of date strings (YYYY-M-D) to an array of goals on that day
 * @param   tasks	   A map of date strings (YYYY-M-D) to an array of tasks on that day
 * @param   nav	       Boolean for displaying the navigation buttons (optional)
 * @return             void
 */

var JiveMonthlyCalendar = Class.create();

JiveMonthlyCalendar.prototype = {

  initialize: function(element, calendar, goals, tasks, nav) {
	this.element    = $(element);
	this.calendar   = calendar;
	this.goals      = goals;
	this.tasks      = tasks;
	this.nav        = nav;
	this.day        = this.calendar.getDayOfMonth();
	this.month      = this.calendar.getMonth();
	this.monthname  = this.calendar.getMonthName();
	this.year       = this.calendar.getYear();
	this.daynames   = JiveCalendar._SDN;
	// Print Calendar
	this.printCalendar();
  },

  getCalendar: function() {
	  return this.calendar;
  },

  setCalendar: function(calendar) {
	  this.calendar = calendar;
  },

  getElement: function() {
	  return this.element;
  },

  setElement: function() {
	  return this.element;
  },

  isNav: function() {
	  return this.nav;
  },

  setNav: function(nav) {
	this.nav = nav
  },

  getMonthlyCalendar: function() {
	   result  = "";

	// Table Vars
	counter = 0;
	day     = 1;
	first   = this.calendar.getFirstDayOfMonth();
	dim     = this.calendar.getDaysInMonth();
	last    = first + dim;
	todaysDate = new JiveCalendar();
	isCurrentMonth = todaysDate.getYear() == this.year && todaysDate.getMonth() == this.month;
	columns = 7;
	rows    = 6;

	// Begin Calendar
	result += "<table cellpadding='0' cellspacing='0' class='jive-calendar'>";
	result += "<tr>";
	// Calendar Heading
	result += "<th class='jive-calendar-month' colspan=\"" + (columns) + "\">" + this.monthname + ", " + this.year;
	if (this.nav) {
		//todo: broken because this refers to the button, not the class. need to use bindAsEventListener, I think
		result += "<span><input type='button' value='&laquo;' onclick='this.prevMonth();'/><input type='button' value='&raquo' onclick='this.nextMonth();'/></div>"
	}
	result += "</th>";
	result += "</tr>";
	result += "<tr>";
	// Weekday Names
	for(i=0; i<columns; i++) {
	  result += "<th class='jive-calendar-weekdays'>" + this.daynames[i] + "</th>";
	}
	result += "</tr>";
	// Weeks
	for(j=0; j<rows; j++) {
	  result += "<tr>";
	  // Days
	  for(k=0; k<columns; k++) {
		result += "<td valign='top' class='jive-calendar-day";

		if(counter >= first && counter < last) {
			if (isCurrentMonth && todaysDate.getDayOfMonth() == day) {
				result += " jive-calendar-today";
			}
			result += "'>";
			result += "<div class='jive-calendar-day-content'><div class='jive-calendar-day-value'>";
			result += day;
			result += "</div>";

			// checkpoints
            if (this.checkpoints) {
                var daycheckpoints = this.checkpoints[this.calendar.getYear() + '-' + this.calendar.getMonth() + '-' + day];
                if (daycheckpoints && daycheckpoints.length > 0) {
                    result += "<a href='#' class='jive-link-checkpoint'><strong>" + daycheckpoints.length;
                    if (daycheckpoints.length == 1) {
                        result += "</strong> Checkpoint</a>";
                    } else {
                        result += "</strong> Checkpoints</a>";
                    }
                }
            }
            // tasks
            if (this.tasks) {
                var daytasks = this.tasks[this.calendar.getYear() + '-' + this.calendar.getMonth() + '-' + day];
                if (daytasks && daytasks.length > 0) {
                    result += "<a href='#' class='jive-link-task'><strong>" + daytasks.length;
                    if (daytasks.length == 1) {
                        result += "</strong> Task</a>";
                    } else {
                        result += "</strong> Tasks</a>";
                    }
                }
            }
            result += "</div>";
			day++;
		} else {
			result += " jive-calendar-noday";
			result += "'>";
		}
		result += "</td>";
		counter++;
	  }
	  result += "</tr>";
	}
	result += "</table>";
	// End Calendar

	return result;
  },

  printCalendar: function() {
   this.element.innerHTML = this.getMonthlyCalendar();
  },

  nextMonth: function() {
	  var calendar = this.calendar.getNextMonth();
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.nav);
  },

  prevMonth: function() {
	  var calendar = this.calendar.getPrevMonth();               
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.nav);
  },

  setDate: function(year, month, day) {
	  var y = 1970;
	  var m = 1;
	  var d = 1;
	  if(year != null) {
		if(typeof(year) == 'number') {
			y = year;
		} else if(typeof(year) == 'string') {
			y = parseInt($(year).value);
		}
	  }
	  if(month != null) {
		if(typeof(month) == 'number') {
			m = month;
		} else if(typeof(month) == 'string'){
			m = parseInt($(month).value);
		}
	  }
	  if(day != null) {
		if(typeof(day) == 'number') {
			d = day;
		} else if(typeof(day) == 'string'){
			d = parseInt($(day).value);
		}
	  }
	  var calendar = new JiveCalendar(y, m, d);
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.nav);
  }

}

/**
 * This is a basic Helper that prints a Tabled Calendar within a specified element. The tabled calendar
 * will start at today and show the next X number of weeks
 *
 * @param   element    Id of the element
 * @param   calendar   the calendar to initialize the upcoming view
 * @param   checkpoints	   A map of date strings (YYYY-M-D) to an array of checkpoints on that day
 * @param   tasks	   A map of date strings (YYYY-M-D) to an array of tasks on that day
 * @param   numWeeks   int for the number of weeks to show (optional, 2 by default)
 * @return             void
 */

var JiveUpcomingCalendar = Class.create();

JiveUpcomingCalendar.prototype = {

  initialize: function(element, calendar, numWeeks) {
	this.element    = $(element);
    this.calendar   = calendar
	if (numWeeks && numWeeks > 0) {this.numWeeks = numWeeks} else {this.numWeeks = 2};
	this.daynames   = JiveCalendar._SDN;
	// Print Calendar
	this.printCalendar();
  },


  getCalendar: function() {
	  return this.calendar;
  },

  setCalendar: function(calendar) {
	  this.calendar = calendar;
  },

  getElement: function() {
	  return this.element;
  },

  setElement: function() {
	  return this.element;
  },

  getNumWeeks: function() {
	  return this.numWeeks;
  },

  setNumWeeks: function(numWeeks) {
	this.numWeeks = numWeeks;
  },

  getUpcomingCalendar: function() {
    // Table Vars
    var counter = 0;
    var day = this.calendar.getDayOfMonth();
    var first = this.calendar.getFirstDayOfMonth();
    var dim = this.calendar.getDaysInMonth();
    var dayOfWeek = this.calendar.getDayOfWeek();
    var columns = 7;
    var rows = this.numWeeks;
    var table = new Element("table", {cellpadding: '0', cellspacing:'0', 'class' : 'jive-calendar', style: 'display: none'});
    var tableHead = new Element("thead");
    table.insert(tableHead);
    var rowHead = new Element("tr");
    tableHead.insert(rowHead);
    for (var i = dayOfWeek; i < dayOfWeek + columns; i++) {
        rowHead.insert(new Element('th', {'class': 'jive-calendar-weekdays'}).update(this.daynames[i % columns]));
    }
    var tableBody = new Element('tbody');
    table.insert(tableBody);
    for (var j = 0; j < rows; j++) {
      var dayRow = new Element("tr");
      tableBody.insert(dayRow);
      // Days
      for (var k = 0; k < columns; k++) {
        if (day > dim) {
          // we have passed the current month, so initialize for next month
          this.calendar = this.calendar.getNextMonth();
          day = this.calendar.getDayOfMonth();
          first = this.calendar.getFirstDayOfMonth();
          dim = this.calendar.getDaysInMonth();
        }
        var dayTd = new Element("td", {valign: 'top', 'class': 'jive-calendar-day' + (j == 0 && k == 0 ? ' jive-calendar-today' : '')});
        dayRow.insert(dayTd);
        var dayContent = new Element('div', {'class': 'jive-calendar-day-content'});
        dayTd.insert(dayContent);
        var dayValue = new Element('div', {'class': 'jive-calendar-day-value'});
        dayContent.insert(dayValue);
        if (j == 0 && k == 0) {
          dayValue.insert(new Element("strong").update('Today'));
        }
        dayValue.insert(day);

        // load any custom objets for the day
        this.loadObjects(dayTd, day);

        day++;
        counter++;
      }
    }
    // End Calendar
    return table;
  },

  loadObjects: function(dayTd, day) {
    // empty, but can be extended to add custom objects per day
  },

  printCalendar: function() {
    var calendar = this.getUpcomingCalendar();
    this.element.update(calendar);
    calendar.toggle();
  },

  nextMonth: function() {
	  var calendar = this.calendar.getNextMonth();
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.numWeeks);
  },

  prevMonth: function() {
	  var calendar = this.calendar.getPrevMonth();
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.numWeeks);
  },

  setDate: function(year, month, day) {
	  var y = 1970;
	  var m = 1;
	  var d = 1;
	  if(year != null) {
		if(typeof(year) == 'number') {
			y = year;
		} else if(typeof(year) == 'string') {
			y = parseInt($(year).value);
		}
	  }
	  if(month != null) {
		if(typeof(month) == 'number') {
			m = month;
		} else if(typeof(month) == 'string'){
			m = parseInt($(month).value);
		}
	  }
	  if(day != null) {
		if(typeof(day) == 'number') {
			d = day;
		} else if(typeof(day) == 'string'){
			d = parseInt($(day).value);
		}
	  }
	  var calendar = new JiveCalendar(y, m, d);
	  this.initialize(this.element, calendar, this.checkpoints, this.tasks, this.numWeeks);
  }

}