/* Magic Mirror
 * Node Helper: Calendar - CalendarFetcher
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 */

var ical = require("ical");
var moment = require("moment");

var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumberOfDays) {
	var self = this;

	var reloadTimer = null;
	var events = [];

	var fetchFailedCallback = function() {};
	var eventsReceivedCallback = function() {};

	/* fetchCalendar()
	 * Initiates calendar fetch.
	 */
	var fetchCalendar = function() {

		clearTimeout(reloadTimer);
		reloadTimer = null;

		ical.fromURL(url, {}, function(err, data) {
			if (err) {
				fetchFailedCallback(self, err);
				scheduleTimer();
				return;
			}

			//console.log(data);
			newEvents = [];

			var limitFunction = function(date, i) {return i < maximumEntries;};

			for (var e in data) {
				var event = data[e];
				var now = new Date();
				var today = moment().startOf("day").toDate();
				var future = moment().startOf("day").add(maximumNumberOfDays, "days").toDate();

				

				// FIXME:
				// Ugly fix to solve the facebook birthday issue.
				// Otherwise, the recurring events only show the birthday for next year.
				var isFacebookBirthday = false;
				if (typeof event.uid !== "undefined") {
					if (event.uid.indexOf("@facebook.com") !== -1) {
						isFacebookBirthday = true;
					}
				}

				if (event.type === "VEVENT") {

					var startDate = (event.start.length === 8) ? moment(event.start, "YYYYMMDD") : moment(new Date(event.start));
					var endDate = (event.end.length === 8) ? moment(event.end, "YYYYMMDD") : moment(new Date(event.end));
					if (event.start.length === 8) {
						startDate = startDate.startOf("day");
					}

					if (typeof event.rrule != "undefined" && !isFacebookBirthday) {
						var rule = event.rrule;
						// console.log("Repeating event ...");
						
						// Check if the timeset is set to this current time.
						// If so, the RRULE line does not contain any BYHOUR, BYMINUTE, BYSECOND params.
						// This causes the times of the recurring event to be incorrect.
						// By adjusting the timeset property, this issue is solved.

						
						if (rule.timeset[0].hour == now.getHours(),
							rule.timeset[0].minute == now.getMinutes(),
							rule.timeset[0].second == now.getSeconds()) {

							rule.timeset[0].hour = startDate.format("H");
							rule.timeset[0].minute = startDate.format("m");
							rule.timeset[0].second = startDate.format("s");
						}

						var dates = rule.between(today, future, true, limitFunction);
						
						for (var d in dates) {
							startDate = moment(new Date(dates[d]));
							newEvents.push({
								title: (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary,
								startDate: startDate.format("x"),
								endDate: endDate.format("x"),
								fullDayEvent: (event.start.length === 8)
							});
						}
					} else {
						// console.log("Single event ...");
						// Single event.
						var fullDayEvent = (event.start.length === 8);
						var title = (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary;

						if (!fullDayEvent && endDate < new Date()) {
							// it's not a fullday event, and it is in the past. So skip.
							console.log("It's not a fullday event, and it is in the past. So skip: " + title);
							continue;
						}

						if (fullDayEvent && endDate < today) {
							// it's a fullday event, and it is before today. So skip.
							console.log("It's a fullday event, and it is before today. So skip: " + title);
							continue;
						}

						if (startDate > future) {
							// it exceeds the maximumNumberOfDays limit. So skip
							console.log("It exceeds the maximumNumberOfDays limit. So skip: " + title);
							continue;
						}

						// Every thing is good. Add it to the list.					
						newEvents.push({
							title: title,
							startDate: startDate.format("x"),
							endDate: endDate.format("x"),
							fullDayEvent: fullDayEvent
						});
						
					}
				}
			}

			newEvents.sort(function(a, b) {
				return a.startDate - b.startDate;
			});

			events = newEvents.slice(0, maximumEntries);

			self.broadcastEvents();
			scheduleTimer();
		});
	};

	/* scheduleTimer()
	 * Schedule the timer for the next update.
	 */
	var scheduleTimer = function() {
		//console.log('Schedule update timer.');
		clearTimeout(reloadTimer);
		reloadTimer = setTimeout(function() {
			fetchCalendar();
		}, reloadInterval);
	};

	/* public methods */

	/* startFetch()
	 * Initiate fetchCalendar();
	 */
	this.startFetch = function() {
		fetchCalendar();
	};

	/* broadcastItems()
	 * Broadcast the exsisting events.
	 */
	this.broadcastEvents = function() {
		//console.log('Broadcasting ' + events.length + ' events.');
		eventsReceivedCallback(self);
	};

	/* onReceive(callback)
	 * Sets the on success callback
	 *
	 * argument callback function - The on success callback.
	 */
	this.onReceive = function(callback) {
		eventsReceivedCallback = callback;
	};

	/* onError(callback)
	 * Sets the on error callback
	 *
	 * argument callback function - The on error callback.
	 */
	this.onError = function(callback) {
		fetchFailedCallback = callback;
	};

	/* url()
	 * Returns the url of this fetcher.
	 *
	 * return string - The url of this fetcher.
	 */
	this.url = function() {
		return url;
	};

	/* events()
	 * Returns current available events for this fetcher.
	 *
	 * return array - The current available events for this fetcher.
	 */
	this.events = function() {
		return events;
	};

};


module.exports = CalendarFetcher;
@@ -3188,74 +3188,8 @@
 %09%09//
- it's not a fullday event, and it is in the past. So skip.%0A%09%09%09%09%09%09%09
 cons
@@ -3351,71 +3351,8 @@
 %09%09//
- it's a fullday event, and it is before today. So skip.%0A%09%09%09%09%09%09%09
 cons
@@ -3498,66 +3498,8 @@
 %09%09//
- it exceeds the maximumNumberOfDays limit. So skip%0A%09%09%09%09%09%09%09
 cons

Disable logging.