/***************************************************************
*  Copyright notice
*
*  (c) 2009 Stephan Schuler <stephan.schuler@netlogix.de>
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*  A copy is found in the textfile GPL.txt and important notices to the license
*  from the author is found in LICENSE.txt distributed with these scripts.
*
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/




/**
 * Client side calendar plotter with ajax connector
 *
 * $Id$
 */

var nxsimplecal = {




	init: function() {
	},




	renderEmptyCalendar: function(calendarDescriptor, monthDescriptor) {

		nxsimplecal.buttonHoverEventStorage = {};

		var calendarWrapper = jQuery(calendarDescriptor.targetField);
		calendarWrapper.append(nxsimplecal.createEmptyMonth(calendarDescriptor, monthDescriptor));

	},




	createEmptyMonth: function(calendarDescriptor, monthDescriptor) {

		var calendarBox = jQuery('<div />')
			.addClass('tx-nxsimplecal-month')
		;

		var displayedDays = {
			displayedDays: 0,
			weekOffset: 0,
			numberOfDaysOfLastMonth: nxsimplecal.getNumberOfDaysOfLastMonth(calendarDescriptor, monthDescriptor)
		};

		var monthHeader = nxsimplecal.createMonthHeader(calendarDescriptor, monthDescriptor);
		calendarBox.append(monthHeader);

		while(displayedDays.displayedDays < monthDescriptor.numberOfDays) {

			var weekBox = nxsimplecal.createEmptyWeek(calendarDescriptor, monthDescriptor, displayedDays);
			calendarBox.append(weekBox);

		}

		return calendarBox;

	},




	getNumberOfDaysOfLastMonth: function(calendarDescriptor, monthDescriptor) {

		var numberOfDaysOfLastMonth = monthDescriptor.dayOfWeekOfFirstOfMonth - calendarDescriptor.firstDayOfWeek;

		if (numberOfDaysOfLastMonth<0) {
			numberOfDaysOfLastMonth += 7;
		}

		return numberOfDaysOfLastMonth;

	},




	createMonthHeader: function(calendarDescriptor, monthDescriptor) {

		var monthHeader = jQuery('<div />');
		monthHeader.addClass('tx-nxsimplecal-monthheader');
	
		var headerText = jQuery('<div />');
		headerText
			.addClass('tx-nxsimplecal-monthheader-headertext')
		;

		var header = jQuery('<h2 />');
		header
			.text('Termine '+monthDescriptor.month_string+' '+monthDescriptor.year)
			.addClass('tx-nxsimplecal-ajaximage')
		;
		headerText.append(header);

		var leftButton = jQuery('<a />');
		leftButton
			.addClass('tx-nxsimplecal-monthheader-leftbutton')
			.text('zurück')
			.click(function() {
				header.addClass('tx-nxsimplecal-ajaxload');
				nxsimplecal.requestMonth(
						calendarDescriptor.calendarViewCounter,
						calendarDescriptor.idPrefix,
						calendarDescriptor.firstDayOfWeek,
						calendarDescriptor.noteboxTemplate,
						monthDescriptor.requestedMonthOffset-1
					);
				})
			;
		monthHeader.append(leftButton);

		monthHeader.append(headerText);

		var rightButton = jQuery('<a />');

		rightButton
			.addClass('tx-nxsimplecal-monthheader-rightbutton')
			.text('vor')
			.click(function() {
				header.addClass('tx-nxsimplecal-ajaxload');
				nxsimplecal.requestMonth(
						calendarDescriptor.calendarViewCounter,
						calendarDescriptor.idPrefix,
						calendarDescriptor.firstDayOfWeek,
						calendarDescriptor.noteboxTemplate,
						monthDescriptor.requestedMonthOffset+1
					);
				})
			;
		monthHeader.append(rightButton);

		return monthHeader;

	},




	createEmptyWeek: function(calendarDescriptor, monthDescriptor, displayedDays) {

		var weekBox = jQuery('<div />')
			.addClass('tx-nxsimplecal-week')
			.addClass('tx-nxsimplecal-week-'+displayedDays.weekOffset)
		;

		if (displayedDays.weekOffset==0 && displayedDays.numberOfDaysOfLastMonth!=0) {
			displayedDays.displayedDays -= displayedDays.numberOfDaysOfLastMonth;
		}

		for (var column=0; column<7; column++) {

			displayedDays.displayedDays++;
			var dayBox = nxsimplecal.createEmptyDay(calendarDescriptor, monthDescriptor, column, displayedDays);
			weekBox.append(dayBox);

		}

		displayedDays.weekOffset++;

		return weekBox;

	},




	createEmptyDay: function(calendarDescriptor, monthDescriptor, column, displayedDays) {

		var dayPointer = '';
		var year = parseInt(monthDescriptor.year);
		var month = parseInt(monthDescriptor.month);
		var day = displayedDays.displayedDays;

		if (day <= 0) {
			month--;
			day = monthDescriptor.numberOfDays_lastMonth + day;
		}

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

		var monthOffset = 'current';

		if (displayedDays.displayedDays <= 0) {
			monthOffset = 'last';
		}
		else if (displayedDays.displayedDays > monthDescriptor.numberOfDays) {
			monthOffset = 'next';
			day = displayedDays.displayedDays - monthDescriptor.numberOfDays;
			month += 1;
			if (month > 12) {
				month = 1;
				year++;
			}
		}

		dayPointer = year+'-'+month+'-'+day;

		var dayBox = jQuery('<div />')
			.addClass('tx-nxsimplecal-day')
			.addClass('tx-nxsimplecal-day-' + dayPointer)
			.addClass('tx-nxsimplecal-day-month-' + monthOffset)
			.addClass('tx-nxsimplecal-column-' + column)
			.addClass('tx-nxsimplecal-monthday-' + day)
			.attr('id', calendarDescriptor.idPrefix + '-' + dayPointer)
			.text(day)
		;

		if (
			day == new Date().getDate()
			&&
			month == new Date().getMonth()+1
			&&
			year == new Date().getFullYear()
		) {
			var dayPointer = jQuery('<span />');
			dayPointer
				.addClass('tx-nxsimplecal-today')
				.text(day);
			dayBox.html(dayPointer);
			dayBox.addClass('tx-nxsimplecal-day-today');
		}

		return dayBox;

	},




	requestMonth: function(calendarViewCounter, idPrefix, firstDayOfWeek, noteboxTemplate, requestedMonthOffset) {

		var queryString = nxsimplecal.requestUrl.replace(
			'###MONTH_OFFSET###',
			requestedMonthOffset
		);

		if(typeof nxsimplecal.ajaxResultsStack[queryString] != 'undefined') {
			nxsimplecal.ajaxSuccess(nxsimplecal.ajaxResultsStack[queryString], calendarViewCounter, idPrefix, firstDayOfWeek, noteboxTemplate, requestedMonthOffset);
		}
		else {
			jQuery.ajax({
				type: 'POST',
				url: queryString,
				data: queryString,
				dataType: 'json',
				success: function(data) {
					nxsimplecal.ajaxResultsStack[queryString] = data;
					nxsimplecal.ajaxSuccess(data, calendarViewCounter, idPrefix, firstDayOfWeek, noteboxTemplate, requestedMonthOffset);
				}
			});
		}

	},




	ajaxSuccess: function(data, calendarViewCounter, idPrefix, firstDayOfWeek, noteboxTemplate, requestedMonthOffset) {

		jQuery('.tx-nxsimplecal-calwrapper-'+calendarViewCounter).removeClass("tx-nxsimplecal-calwrapper-ajaxloader");

		var calendarDescriptor = {
			targetField: '.tx-nxsimplecal-calwrapper-'+calendarViewCounter,
			idPrefix: idPrefix,
			firstDayOfWeek: firstDayOfWeek,
			calendarViewCounter: calendarViewCounter,
			noteboxTemplate: noteboxTemplate
		};

		nxsimplecal.clearOldCalendar(calendarDescriptor);

		data.month.requestedMonthOffset = requestedMonthOffset;

		nxsimplecal.renderEmptyCalendar(
			calendarDescriptor,
			data.month
		);

		nxsimplecal.addEventFieldsToCalendar(
			calendarDescriptor,
			data.events
		);

	},




	clearOldCalendar: function(calendarDescriptor) {

		jQuery(calendarDescriptor.targetField).empty();

	},




	addEventFieldsToCalendar: function(calendarDescriptor, eventsDescriptor) {

		var differentEventDates =  {};

		jQuery(eventsDescriptor).each(function(eventDataKey, eventData) {
			differentEventDates[eventData.from_idDescriptor] = [];
		});

		jQuery(eventsDescriptor).each(function(eventDataKey, eventData) {
			differentEventDates[eventData.from_idDescriptor].push(eventData);
		});

		var eventsInfoWrapper = jQuery('<div />');

		jQuery('body').append(eventsInfoWrapper);

		jQuery.each(differentEventDates, function(dayIdentifier, eventsList) {
			nxsimplecal.drawSingleDaysEvents(calendarDescriptor, dayIdentifier, eventsList, eventsInfoWrapper);
		});

	},




	drawSingleDaysEvents: function(calendarDescriptor, dayIdentifier, eventsList, eventsInfoWrapper) {

		var buttonField = jQuery('#'+calendarDescriptor.idPrefix+'-'+dayIdentifier);

		var monthDay = dayIdentifier.split('-')[dayIdentifier.split('-').length-1];

		var noteBox = jQuery('<div />')
			.attr('id', (calendarDescriptor.idPrefix)+'-'+dayIdentifier+'-notebox')
			.addClass('tx-nxsimplecal-notebox')
			.addClass('tx-nxsimplecal-notebox-allnotestype-'+eventsList[0]['type'])
			.addClass('tx-nxsimplecal-notebox-allnotestype-monthday-'+monthDay+'-'+eventsList[0]['type'])
			.css({
				position: 'absolute',
				top: buttonField.offset()['top'],
				left: buttonField.offset()['left']+buttonField.width()+2,
				display: 'none' //TODO: tooltip-auto-hide here
			})
		;

		buttonField
			.addClass('tx-nxsimplecal-eventday')
			.addClass('tx-nxsimplecal-eventday-allnotestype-'+eventsList[0]['type'])
			.addClass('tx-nxsimplecal-eventday-allnotestype-monthday-'+monthDay+'-'+eventsList[0]['type'])
			.mouseover(function() {nxsimplecal.noteBoxHoverIn(buttonField, noteBox, eventsInfoWrapper);})
			.mouseout(function() {nxsimplecal.noteBoxHoverOut(buttonField, noteBox, eventsInfoWrapper);})
		;

		noteBox
			.mouseover(function() {nxsimplecal.noteBoxHoverIn(buttonField, noteBox, eventsInfoWrapper);})
			.mouseout(function() {nxsimplecal.noteBoxHoverOut(buttonField, noteBox, eventsInfoWrapper);})
		;

		var noteBoxWrapper = jQuery('<div />');
		noteBoxWrapper.addClass('tx-nxsimplecal-noteboxwrapper');

			var noteBoxWrapperTop = jQuery('<div />');
			noteBoxWrapperTop.addClass('tx-nxsimplecal-noteboxwrapper-top');

			var noteBoxWrapperMiddle = jQuery('<div />');
			noteBoxWrapperMiddle.addClass('tx-nxsimplecal-noteboxwrapper-middle');

			var noteBoxWrapperBottom = jQuery('<div />');
			noteBoxWrapperBottom.addClass('tx-nxsimplecal-noteboxwrapper-bottom');

		noteBoxWrapper
			.append(noteBoxWrapperTop)
			.append(noteBoxWrapperMiddle)
			.append(noteBoxWrapperBottom)
		;

		jQuery.each(eventsList, function(singleEventKey, singleEvent) {
			nxsimplecal.drawSingleEvent(calendarDescriptor, singleEvent, noteBoxWrapperMiddle);
		});

		noteBox.append(noteBoxWrapper);

		eventsInfoWrapper.append(noteBox);

	},




	drawSingleEvent: function(calendarDescriptor, singleEvent, noteBox) {

		var singleNote = jQuery('<div />')
			.addClass('tx-nxsimplecal-notebox-singlenote')
			.addClass('tx-nxsimplecal-noteblock-singlenotetype-'+singleEvent['type'])
			.html(
				calendarDescriptor.noteboxTemplate
					.replace(
						'###TITLE###',
						singleEvent.title
					)
					.replace(
						'###MORE###',
						singleEvent.more
					)
					.replace(
						'###LOCATION###',
						singleEvent.location
					)
					.replace(
						'###FROM_READABLE###',
						nxsimplecal.getReadableDate(singleEvent.from, calendarDescriptor)
					)
					.replace(
						'###TO_READABLE###',
						nxsimplecal.getReadableDate(singleEvent.to, calendarDescriptor)
					)
					.replace(
						'###DATE###',
						(nxsimplecal.getReadableDate(singleEvent.from, calendarDescriptor) == nxsimplecal.getReadableDate(singleEvent.to, calendarDescriptor) || singleEvent.to == 0)
							?	nxsimplecal.getReadableDate(singleEvent.from, calendarDescriptor)
							:	nxsimplecal.getReadableDate(singleEvent.from, calendarDescriptor)+' - '+nxsimplecal.getReadableDate(singleEvent.to, calendarDescriptor)
					)
			)
		;
		noteBox.append(singleNote);

	},




	getReadableDate: function(unixTimestamp, calendarDescriptor) {

		var date = new Date(unixTimestamp * 1000);
		return date.getDate()+'.'+(date.getMonth()+1)+'.';

	},




	requestUrl: '',




	noteBoxHoverIn: function(buttonField, noteBox, eventsInfoWrapper) {

		window.clearTimeout(nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')]);
		nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = false;

		nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = window.setTimeout(function() {
			nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = false;
			jQuery('.tx-nxsimplecal-notebox').each(function(i, anyNoteBlock) {
				jQuery(anyNoteBlock).css({zIndex: 500});
				nxsimplecal.hideNoteBlock(jQuery(anyNoteBlock));
			});
			noteBox.css({zIndex: 550});
	
			noteBox.stop();
			noteBox.show();
			noteBox.animate({ 
					marginLeft: 10,
					opacity: "1"
				},
				400,
				function() {
					noteBox.css({zIndex: 550});
				}
			);
		}, 500);

	},




	noteBoxHoverOut: function(buttonField, noteBox, eventsInfoWrapper) {

		window.clearTimeout(nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')]);
		nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = false;

		nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = window.setTimeout(function() {
			window.clearTimeout(nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')]);
			nxsimplecal.buttonHoverEventStorage[buttonField.attr('id')] = false;
			nxsimplecal.hideNoteBlock(noteBox);
		}, 100);

	},




	hideNoteBlock: function(noteBox) {
		if(!nxsimplecal.doFadeOut) {
			noteBox.css({display: 'none'});
		}
		noteBox.stop();
		noteBox.animate({ 
				marginLeft: 0,
				opacity: ".4"
			},
			400,
			function(){
				noteBox.hide();
			}
		);
	},




	/**
	 * Client side caching of ajax call results
	 */
	ajaxResultsStack: {},




	/**
	 * References to buttons hovering at the moment
	 */
	buttonHoverEventStorage: {},




	/**
	 * Defines if events have to fade out (true) or disappear immedaitely (false)
	 */
	doFadeOut: false




};



