/*
* Title:  jcal
* Dependencies:  jQuery 1.3.0 +
* Author:  Fredrik Karlsson
* Email:  fredrik@fkinnovation.se
*/
var g_events = {};

(function($) {
	
	/*
	  Define language variables for weekday and month names
	  Example: lang['eng'].month_titles[0] returns 'January'
	*/
	var langs = {
		"swe": {
			"month_titles" : ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"],
			'weekday_titles' : ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"]
		},
		"eng": {
			'month_titles' : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
			'weekday_titles' : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
		},
		"ger": {
			'month_titles' : ["Januar", "Februar", "März", "Avril", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
			'weekday_titles' : ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]
		},
		"fr": {
			"month_titles" : ["Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Decembre"],
			"weekday_titles" : ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"]
		}
	};	
	
	/*
	  Plugin function
	*/
	$.fn.jscal = function(options)
	{
		var elem = $(this);
		
		var now = new Date();
		
		var settings = {
			'month': now.getMonth(),
			'year': now.getFullYear(),
			'day': now.getDate(),
			'firstWeekDay': 1,
			'itemWidth': 26,
			'itemPadding': 1,
			'lang': 'eng',
			'events': {},
			'eventsUrl' : ''
		};
		
		if(options) { $.extend(settings, options); }
		
		/*
		  Setup previous and next month dates
		*/
		var prevMonth = new Date(settings.year, settings.month-1);
		var prevDays = daysInMonth(prevMonth.getMonth(), prevMonth.getFullYear());
		var nextMonth = new Date(settings.year, settings.month+1);
		var shownPrevDays = 0;
		
		
		this.init = function() {
			/*
			 If the user supplied an url to an external json file,
			 load it into the events object before rendering the calendar
			*/
			if(settings.eventsUrl != '') {
				this.loadEvents(settings.eventsUrl);
			}
			/*
			 If the user supplied events as an json object directly, save it
			 to the local json-object before rendering the calendar
			*/
			else if(typeof settings.events == 'object' && settings.events.events.length > 0){
				this.loadEvents(settings.events);
			}
			/*
			 If the user didn't supply any events, just render the calendar
			*/
			else {
				this.renderCal();
			}
		}
		
		
		/*
		 Render the calendar (duh!)
		*/
		this.renderCal = function()
		{
			var obj = this;
			
			var daysInCurrentMonth = 0;
			var counter = 0;
			var startWeekday = 0;
			var weekdayname = '';
			
			var calevents = [];
			var caldata = '';
			var classtext = '';
			var numCalEvents = '';
			
			var leftOverDays = 0;	
            
            /*
	            Set the initial date
            */
            var dd = new Date(settings.year, settings.month);            		
			
			var cal = $('<div id="calendar"/>');
			
			var prev = $('<a class="prev" href="#" />');
			var next = $('<a class="next" href="#" />');
			
			$(prev).click(function() { obj.changeMonth(-1); return false; });
			$(prev).text('<');
			$(next).click(function() { obj.changeMonth(+1); return false; });
			$(next).text('>');
			
            var title = $('<div id="title" />');
            $(cal).append(title);
			/*
			 If there are any previous months this year, print out the prev button
			*/
			if(!(settings.month-1 == -1)){
				$(title).append(prev);
			}
			
			$(title).append('<h2>' + getMonthName(settings.month, settings.lang) + ' ' + settings.year + '</h2>');
			
			/*
			 If there are any more month this year, print out the next button
			*/
			if(!(settings.month+1 == 12)) {
				$(title).append(next);
			}

			/*
			 Create and append an unordered list to hold all our date items
			*/
			var ul = $('<ul/>');
			$(cal).append(ul);
			$(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[0].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[1].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[2].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[3].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[4].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[5].substr(0,1) + '</em></a></li>');
            $(ul).append('<li class="day"><a><em>' + langs.eng.weekday_titles[6].substr(0,1) + '</em></a></li>');
			/*
			 Set the day to the first day of the month to figure out which weekday the month starts with
			*/
			dd.setDate(1);
			startWeekday = (dd.getDay());

            //console.log("dd.getDay: " + dd.getDay());
            //console.log("dd.getFullYear: " + dd.getFullYear());
			
			/*
			 If the starting weekday is anything other than the chosen first weekday (mon/sun),
			 print dates from the previous month until we hit the starting weekday
			*/
            
            //console.log('startWeekDay: ' + startWeekday);
            //console.log('settings.firstWeekDay: ' + settings.firstWeekDay);
            
			if((startWeekday > settings.firstWeekDay) || (startWeekday == 0 && settings.firstWeekDay == 1))		{		
				if(startWeekday == 0 && settings.firstWeekDay == 1) {
					counter = 6;
				} else {
					counter = (startWeekday-settings.firstWeekDay);
				}
				
				shownPrevDays = counter;
				j = prevDays-counter+1;
				
				for(var i = 0; i < (counter); i++) {
					$(ul).append('<li><a href="#" class="prevMonth"><span>' + getWeekDayName(j, prevMonth.getMonth(), prevMonth.getFullYear(), settings.lang) + '</span><em>' + j + '</em></a></li>');
					j = j + 1;
				}
			}
		
			daysInCurrentMonth = daysInMonth(settings.month, settings.year);
		
			/*
			 Start printing out the current month
			*/
			for(var i = 1; i < (daysInCurrentMonth+1); i++ ) {
				weekdayname = getWeekDayName(i, settings.month, settings.year, settings.lang)
				
				/*
				 Look for any events ocurring on the current date.
				 If any events are found, add the event id's to the data-events
				 attribute of the current <a> element.
				*/
				calevents = findEvents(settings.year, settings.month, i);
				caldata = '';
				classtext = '';
				numCalEvents = '';
				
				if(calevents.length > 0) {
					numCalEvents = '<small>' + calevents.length + '</small>';
					for(var j in calevents) {
						if(j>0) { caldata += ","; }
						caldata += calevents[j].id;
					}
					classtext = 'class="event" ';
				}
				$(ul).append('<li><a ' + classtext + 'href="#" data-events="' + caldata + '"><span>' + weekdayname + numCalEvents + '</small></span><em>' + i + '</em></a></li>');
			}
			
			
			/*
			 Calculate if we need to print out any additional days from next month to fill the 'grid'
			*/
			leftOverDays = (42-(daysInCurrentMonth+shownPrevDays));
			
			for(var i = 1; i <= leftOverDays; i++) {
				$(ul).append('<li><a href="#" class="nextMonth"><span>' + getWeekDayName(i, nextMonth.getMonth(), nextMonth.getFullYear(), settings.lang) + '</span><em>' + i + '</em></a></li>');
			}


			/*
				Look for any events ocurring on the current date.
				If any events are found, add the event id's to the data-events
				attribute of the current <a> element.
			*/
            var curdate = new Date();
			calevents = findEvents(curdate.getFullYear(), curdate.getMonth(), curdate.getDate());
			caldata = '';
			classtext = '';

			var todayEvent = $('<div id="todayEvent" />');
			
			$(cal).append(todayEvent);
			
			if(calevents.length > 0) {
				$(todayEvent).text(calevents[0].text);
                //$(cal).append('<div id="todayEvent">' + + '</div>');
			}
			
			/*
			 Apply some styles to the calendar and its items
			*/
			$(cal).css({
				width: (settings.itemWidth+(settings.itemPadding*2))*7 + "px"
			}).find('a').css({
				width: settings.itemWidth + "px",
				padding: "1px"
			});			
			$(elem).html($(cal));
			
			/*
			 Show event text on mouseover
			*/
			
			var oldText = "";
			
			$('a.event').hover(function()
			{
				var id = $(this).attr('data-events');
				var eventPos = parseInt(getEventPos(id));
				oldText = $(todayEvent).text();
				//alert(g_events['events'][eventPos].text);
				$(todayEvent).text(g_events['events'][eventPos].text);
				//alert('yay');
			},
			function() {
				$(todayEvent).text(oldText);
			});
		}
		
		
		/*
		 Load events from json
		*/
		this.loadEvents = function(events) {
			
			var obj = this;
			
			if(typeof events == 'object') {
				g_events = events;
				obj.renderCal();
			}
			else if(events != '') {
				$.ajax({
					type: 'GET',
					url: events,
					dataType: 'json',
					cache: false,
					success: function(data, textStatus, jqXHR) {
						g_events = data;
						obj.renderCal();
					},
					error: function(jqXHR, textStatus, errorThrown) {
						alert('An error occured - (' + textStatus + ', ' + errorThrown + ')');
					}
				});
			}
		}
		
		this.changeMonth = function(newMonth) {
			settings.month = settings.month + newMonth;
			this.renderCal();
		}
		
		this.init();
	}

	
	/*
	 Returns the number of days of the given month/year.
	 By setting the current month in the future and then setting an invalid date,
	 the Date object falls back to the last day of the previous month, automatically
	 giving us the correct number of days
	*/
	function daysInMonth(month,year) {
		var dd = new Date(year, month+1, 0);
		return dd.getDate();
	}
	
	
	/*
	 Returns the position of the given event
	*/
	function getEventPos(eventID) {
		var found = false;
		var i = 0;
		for(i in g_events['events']) {
			if(g_events['events'][i].id == eventID) {
				found = true;
				break;
			}
		}
		if(found == true) {
			return i;
		}
		else {
			return false;
		}
	}
	
	
	/*
	 Returns the translated name of the given weekday.
	*/
	function getWeekDayName(day, month, year, lang) {
		var dd = new Date(year, month, day);	
		var weekday = dd.getDay();
		return langs[lang].weekday_titles[weekday].substr(0,2);
	}
	
	
	/*
	 Returns the translated name of the given month.
	*/
	function getMonthName(month, lang) {
		return langs[lang].month_titles[month];
	}
	
	
	/*
	 Searches the event object for any events occuring on the given date and
	 returns an array of events
	*/
	function findEvents(year, month, day) {
        //console.log("y: " + year + ", m: " + month + ", d: " + day);
		var parseDate = year + "-" + (month+1) + "-" + day;
		var calevents = [];
		for(var i in g_events.events) {
			var eventdate = g_events.events[i].eventdate;
			if(parseDate == eventdate) {
				calevents.push(g_events.events[i]);
			}
		}
		
		return calevents;
	}
	
})(jQuery);
