SidebarHelperSrvc.js

angular.module('homepage').
factory('SidebarHelperSrvc', function (DateUtility, TemplateTimelineService) {
	// Store the original data templates copy here (READ ONLY)
	var DataStore = {
		habit: {
			templates: []
		},
		calendar: {
			templates: []
		}
	};

	// Store processed data here. Do not reinitialise object references elsewhere
	var sidebar = {
		habit: new TaskItems(),
		calendar: new TaskItems(),
		all: new TaskItems()
	};

	// Object structure used to store habit and calendar tasks
	function TaskItems() {
		return {
			pending: {},
			current: {
				morning: [],
				afternoon: [],
				evening: [],
				night: []
			},
			future: {}
		};
	}

	// NOTE: Any change within sidebar object will update the sidebar
	// Complete sidebar object is passed to sidebar module
	function resetSidebar(type) {
		switch(type) {
			case 'CLDR':
				sidebar.calendar = new TaskItems();
				break;
			case 'HABT':
				sidebar.habit = new TaskItems();
				break;
			default:
				sidebar.habit = new TaskItems();
				sidebar.calendar = new TaskItems();
				break;
		}

		sidebar.all = new TaskItems();
	}

	function updateDataStore(data) {
		if(data.type == 'HABT') {
			DataStore.habit.templates.push(data);
		}
		if(data.type == 'CLDR') {
			DataStore.calendar.templates.push(data);
		}
	}

	function updateSidebarData(data) {
		if(data.type == 'HABT') {
			updateHabitData(data);
		}
		if(data.type == 'CLDR') {
			updateCalendarData(data);
		}
		mergeAllData();
	}

	/**
	 * Adding entries that are to be shown for today
	 * @param  {[type]} data [description]
	 * @return {[type]}      [description]
	 */
	 function updateHabitData(data) {
	 	addItem(data);
	 }

	 function updateCalendarData(data) {
		// CHECK DATE RANGE
		// Add item, if today falls in date range
		var today = new Date();
		var from  = data.data.dates.START.date;
		var to    = data.data.dates.END.date;
		if(DateUtility.isBetweenDates(today, from, to, true, true)) {
			addItem(data);
		}
	}

	/**
	 * Merge habit and calendar item objects
	 * @return {[type]} [description]
	 */
	function mergeAllData() {
		var morning = sidebar.habit.current.morning.concat(sidebar.calendar.current.morning);
		var afternoon = sidebar.habit.current.afternoon.concat(sidebar.calendar.current.afternoon);
		var evening = sidebar.habit.current.evening.concat(sidebar.calendar.current.evening);
		var night = sidebar.habit.current.night.concat(sidebar.calendar.current.night);
		// Assign new array instance
		sidebar.all.current.morning = morning.slice();
		sidebar.all.current.afternoon = afternoon.slice();
		sidebar.all.current.evening = evening.slice();
		sidebar.all.current.night = night.slice();
	}

	/**
	 * Form task item to be passed to template
	 * @param  {[type]} data [description]
	 * @return {[type]}      [description]
	 */
	function getItem(data) {
		var item = {};
		item.hashid = data.data.hashid;
		item.isChecked = data.data.isChecked;

		if(data.type == 'HABT') {
			// Habit with trail and time
			if(data.data.time.code == 'TIME') {
				item.type = 'HBTT';
				item.label = data.data.title;
				item.date = data.data.time.date;
			}
			// Habit with trail only
			else {
				item.type = 'HBTR';
				item.label = data.data.title;
			}
		}
		if(data.type == 'CLDR') {
			item.label = data.data.title ? data.data.title : 'Event';

			// Calendar meeting with time and location
			if(data.data.placetext && data.data.times.START.isDateSet) {
				item.type = 'CMTL';
				item.times = data.data.times;
				item.locationText = data.data.placetext;
			}
			// Calendar reminder based on time
			else if(data.data.times.START.isDateSet) {
				item.type = 'CRBT';
				item.times = data.data.times;
			}
			// Calendar reminder without time
			else if(!data.data.times.START.isDateSet) {
				item.type = 'CMWT';
			}
		}
		return item;
	}

	/**
	 * Add item to sidebar data as per time information
	 */
	function addItemEntry(data, code) {
		var today = new Date();
		var time;

	 	if(code == 'HABT') {
	 		type = 'habit';
	 		time = data.data.time.date;
	 		code = data.data.time.code || 'TIME';
	 	}
	 	else if(code == 'CLDR') {
	 		type = 'calendar';
	 		time = data.data.times.START.date;
	 		code = 'TIME';
	 	}

		time = new Date(time);

		// CHECK TIME
		// Add as per time else add to current time
		if(code == 'MRNG' || (code == 'TIME' && (time.getHours() >= 6 && time.getHours() < 12))) {
			sidebar[type].current.morning.push(getItem(data));
		}
		else if(code == 'AFTN' || (code == 'TIME' && (time.getHours() >= 12 && time.getHours() < 17))) {
			sidebar[type].current.afternoon.push(getItem(data));
		}
		else if(code == 'EVNG' || (code == 'TIME' && (time.getHours() >= 17 && time.getHours() < 20))) {
			sidebar[type].current.evening.push(getItem(data));
		}
		else if(code == 'NGHT' || (code == 'TIME' && (time.getHours() >= 20 && time.getHours() < 24))) {
			sidebar[type].current.night.push(getItem(data));
		}
		else if(code == 'NONE' || code == 'FLDY' ||
			(code == 'TIME' && (today.getHours() >= 0 && today.getHours() < 6))) {
			if(today.getHours() >= 6 && today.getHours() < 12) {
				sidebar[type].current.morning.push(getItem(data));
			}
			else if(today.getHours() >= 12 && today.getHours() < 17) {
				sidebar[type].current.afternoon.push(getItem(data));
			}
			else if(today.getHours() >= 17 && today.getHours() < 20) {
				sidebar[type].current.evening.push(getItem(data));
			}
			else {
				sidebar[type].current.night.push(getItem(data));
			}
		}
	}

	function addItem(data) {
		var days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

		// CHECK REPETITION
		// If Once, check if timestamp matches today
		// If Daily, add entry for today
		// If Weekly, check if today falls in the choice made
		// If Monthly, repeat on same day as timestamp each month
		// If Annually, repeat on same date as timestamp each year
		var repeats = data.data.repetition.repeats;
		var today = new Date();
		if(repeats == 'ONCE') {
			if(DateUtility.compareDateOnly(data.timestamp, today) === 0) {
				addItemEntry(data, data.type);
			}
		}
		else if(repeats == 'DALY') {
			addItemEntry(data, data.type);
		}
		else if(repeats == 'WEEK') {
			var type = data.data.repetition.chooseday.type;
			var dayofweek = days[today.getDay()];
			var chosen = data.data.repetition.chooseday.days;
			for(var index in chosen) {
				var choice = chosen[index];
				if(dayofweek == choice) {
					addItemEntry(data, data.type);
				}
			}
		}
		else if(repeats == 'MTLY') {
			if(today.getDate() == new Date(data.timestamp)) {
				addItemEntry(data, data.type);
			}
		}
		else if(repeats == 'ANLY') {
			if(today.getDate() == new Date(data.timestamp).getDate()
				& today.getMonth() == new Date(data.timestamp).getMonth()) {
				addItemEntry(data, data.type);
			}
		}
	}

	return {
		/**
		 * Initialize all the data using the list of templates received
		 */
		initialize: function (templates, type) {
			// Reinitialize all data before processing all items
			// Resetting without size check would empty all items,
			// if habits or calendar items are null and no merge is called
			if(templates.length > 0) {
				resetSidebar(type);
			}

			// Process templates only applicable for today
			templates = TemplateTimelineService.getItemsByDate(templates);

			for(var index in templates) {
				var template = templates[index];
				updateSidebarData(template);
			}

			return sidebar;
		},
		getSidebarByDate: function (templates) {
			this.initialize(DataStore.habit.templates, 'HABT');
			this.initialize(DataStore.calendar.templates, 'CLDR');
			return sidebar;
		},
		/**
		 * Return the sidebar object
		 */
		getSidebarData: function () {
			return sidebar;
		},
		update: function (data) {
			updateDataStore(data);
			updateSidebarData(data);
			return sidebar;
		},
		/**
		 * Reset data store
		 */
		resetAll: function () {
			DataStore.habit.templates.length = 0;
			DataStore.calendar.templates.length = 0;
			resetSidebar();
		}
	}
});