/**
* Inspiring Apps extension to MooTools ECalendar.
*
* Adds custom AJAX-driven calendar data query as well as mini-caching of 
* calendar data to reduce SQL load for switching views repeatedly.
*
* @author Mathias Gran <mathias@inspiringapps.com>
* @copyright 2009 Inspiring Applications, Inc.
*
* @todo Add security features for JAX calls.
*/

/**
 * ajax call, sends form data for notification request.
 */
function sendNotificationRequest(divID, formName) {
	var divPop = document.getElementById(divID);
	var req = new Request({
		method: 'get',
		url: '/time/services/calendarfeedEvent.php',
		data: {
			action: 'save',
			eid: document.forms[formName]['eid'].value,
			quantity: document.forms[formName]['quantity'].value,
			denomination: document.forms[formName]['denomination'].value,
			email: document.forms[formName]['email'].value,
			customer_member_id: document.forms[formName]['customer_member_id'].value
		},
		onRequest: null,
		onComplete: function(response) {
			var _userMessage = new Element('div', {
				'class':'manage_error calendar_notification'
			});
			_userMessage.set('html', response);
			
			var notifyDiv = $('notificationBox');
				notifyDiv.empty();
				
			_userMessage.inject(notifyDiv);
		}.bind(this)
	}).send();
}

var iaMooCalendar = new Class({
		Extends: Calendar,
				
		options: {
			isIaMooCal: true,
			isQuickView: false,
			newDate: 0,
			divPop: 0,
			filter: '',
			filterID: 0,
			userViewFilter: '',
			eventFeedTarget: '/time/services/calendarfeedEvent.php'
		},
		
		// Overrides the mooECal initialize method:
		initialize: function(options){
			// Copied from mooECal initialize:
			this.setOptions(options);
			this.extendDate();
			this.days = ['S', 'M', 'T', 'W', 'Th', 'F', 'Sa'];
			this.dayNames = ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.'];
			this.months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
			this.daysInMonth = 30; // can be set with setDaysInMonth(month,year)
			this.options.newDate != 0 ? this.calDate = new Date(this.options.newDate) : this.calDate = new Date();
			this.startingOffset = 0; // determine the offset of the first of the month and Sunday - used for the "month" view
			this.viewStartDate = new Date(); // starting date for current view
			this.viewEndDate = new Date(); // ending date for current view
			this.gotEvents = false; // initial request for the events feed
			this.eventRangeStart = new Date(); //current range of events that have been fetched
			this.eventRangeEnd = new Date();
			this.setCalParams();
			
			//
			// Only render the calendar if it's not the quick-view and
			// the target DOM element exists:
			//
			if( !this.options.isQuickView && $(this.options.calContainer) != null ) {
				switch(this.options.view){
					case 'month':
						this.showMonth();
						break;
					case 'week':
						this.showWeek();
						break;
					case 'day':
						this.showDay();
						break;
					default:
						this.showMonth();
				}
			}
		},
		
		// JS Object to manage caching
		cache: {
			expires: false,
			monthCached: -1,
			
			/**
			 * Check to see if the cache has expired:
			 * @return bool
			 */
			 isCurrent: function() {
				 if( !this.expires ) return false;
				 
				 var _dt = new Date();
				 return ( _dt.getTime() < this.expires.getTime() );
			 },
			
			
			/**
			 * Updates cache expiry:
			 * Default: 3 minutes = 180 sec.
			 *
			 * this == iaMooCalendar.cache
			 */
			extendCacheExpires: function() {
				this.expires = new Date();
				this.expires.setTime( this.expires.getTime() + (1000 * 180) );
			},
			
			/** 
			 * Forces the cache to expire - good to call on updates.
			 */
			 expireCache: function() {
				 this.expires = false;
				 this.monthCached = -1;
			 }
		},
		
		// AJAX requests to grab data:
		getMonthlyCalendarData: function() {
			// Don't send AJAX call if our cache is current for THIS month
			if( this.calDate.getMonth() == this.cache.monthCached
			&&  this.cache.isCurrent() ) {
					// Debug:
					//alert('cached');
					//_now = new Date();
					//console.log('Using Cached event feed... (Cache Expires: ' + ((this.cache.expires.getTime() - _now.getTime())/1000.00) + ' sec.)');
					
					//this.loadCalEvents('Ignore Call');
					return;
			}
			
			// Debug:
			//console.log('Grabbing new event feed...');
			
			// Empty any stored info:
			//this.options.cEvents = [];
			//this.cache.monthCached = -1;
			
			// JSON request with this.calDate.getMonth()
			// getMonth returns 0-index of current month: Jan == 0, Feb == 1, etc.
			
			var _ajax = new Request.JSON({
					url: '/time/services/calendarfeed.php',
					method: 'get',
					noCache: true,
					async: false,  // wait til it's done.
					data: {
						action: 'getMonthlyEvents',
						month: this.calDate.getMonth(),
						year: this.calDate.getFullYear(),
						filter: this.options.filter,
						userViewFilter: this.options.userViewFilter,
						id: this.options.filterID
					},
					onSuccess: function(eventsObject, eventsText) {
						// Debug:
						//alert(eventsText);
				        //console.log(this.options.cEvents);
						//console.log(eventsObject);
						
						// Set the events:
						//this.options.cEvents = [];
						this.options.cEvents = eventsObject;
						//console.log(this.options.cEvents);
						
						this.cache.monthCached = this.calDate.getMonth();
						this.cache.extendCacheExpires();
						
					}.bind(this)
			}).send();
			
			//this.loadCalEvents('After Jax');
		},
		
		/**
		 * Overriding mooECal function to opt-out of rendering if the target element does not exist.
		 * @param string _referrer (optional) a note to help you determine where the call came from.
		 */
		loadCalEvents: function( _referrer ) {
			//
			// Only render the calendar if the target DOM element exists:
			//
			if( $(this.options.calContainer) == null ) return;
			
			// Else call the parent method:
			//this.parent();
			
			var time = '';
			$$('div.tip').each(function(divs){divs.getParent().destroy();}); // Tips cleanup - tip divs kept building up after switching calendar views
			for(var i = 0; i < this.options.cEvents.length; i++){
				var eStart = new Date();
				eStart.setISO8601(this.options.cEvents[i].start);
				time = (this.options.cEvents[i].start.toString().match(new RegExp(/(\d\d\d\d-\d\d-\d\dT)/))) ? eStart.thTime() : '';
				if(eStart >= this.viewStartDate && eStart <= this.viewEndDate){
					var eventDiv = new Element('div',{
						'html':time+' '+this.options.cEvents[i].title//,
						// 'title': this.options.cEvents[i].title // For Moo Tips plugin
					}).store('date',eStart.getDate()).inject($('day'+eStart.getDate()).getChildren('div')[0]);
					
					if (this.options.view != 'month') // the month view only shows a portion of the event description
					{
						eventDiv.addClass('fullEvent');
					}
					// For Moo's Tips implementation:
					//eventDiv.addClass('eventTips');
					if(this.options.scroller)
						new Scroller($('day' + eStart.getDate()).getChildren('div')[0],{'area':20}).start(); //add Scroller to month view days
											
					// create base div for the popup
					if( this.divPop == null ) {
						this.divPop = new Element( 'div', {'html':'', 'id':'divPopupContainer'+i, 'class':'divPopupContainer', 'styles':{ 'position':'absolute', 'display':'block', 'height':'auto'  } } );
						this.divPop.inject( $(document.body), 'top' );
						this.divPop.setStyles( { opacity:0, display:'block' } );
					}
					
					//
					// Non Moo Tips Plugin:
					//
					// create tip div for hover
					if( this.divTip == null ) {
						this.divTip = new Element( 'div', {
								'html': '',
								'id': 'calDivTip',
								'class': 'calDivTip'
						});
						this.divTip.inject( $(document.body), 'top' );
					}
					// tip div show event
					eventDiv.addEvent('mouseenter', function(event, i, eventDiv) {
						this.divTip.setProperty('html', this.options.cEvents[i].title);
						this.divTip.position({ x: (event.page.x + 15), y: (event.page.y + 15) });
						this.divTip.setStyle('display', 'block');
					}.bindWithEvent(this, [i, eventDiv]));
					// tip div hide event
					eventDiv.addEvent('mouseleave', function() {
						this.divTip.setProperty('html', '');
						this.divTip.setStyle('display', 'none');
					}.bind(this));
					// */
					
					// For Moo's Tips implementation:
					//eventDiv.addClass('eventTips');
					
					
					eventDiv.setStyle( 'cursor', 'pointer' );
					
					// an event was clicked
					eventDiv.addEvent('click', function( event, i, eStart, time, eventDiv ) { 
						// Hide any exiting non-moo tool tips:
						this.divTip.setStyle('display', 'none');
						
						// ajax call, passes eventID from the JSON feed and a 'getEvent' action
						var req = new Request({
							method: 'get',
							//url: '/time/services/calendarfeedEvent.php',
							url: this.options.eventFeedTarget,
							data: {
								eid: this.options.cEvents[i].eventID,
								effective_start_date: this.options.cEvents[i].effectiveStart,
								effective_end_date: this.options.cEvents[i].effectiveEnd
								},
							onRequest: null,
							onComplete: function(response) { 
								this.divPop.setProperty( 'html', response );
								
								this.divPop.getElement('a.divPopupClose').addEvent('click', function( eventInner, i, event ) { 
									eventInner.stop();
									this.divPop.fade('hide')
								}.bindWithEvent( this, i, event ));
								
								//We're setting the onClick event logic for the popup for the "Edit" button.
								this.divPop.getElement('a.divPopupEdit').addEvent('click', function( eventInner, i, event ) {
									
										if( this.options.cEvents[i].isRecurrence == true )
										{
											eventInner.stop();
											this.divPop.fade('hide');
											
											if( !window._mooDialog )
											{
												alert('Unable to locate the _mooDialog class.');
											}
											else
											{
												window._mooDialog.fetchDialog({
													'action': 'RecurrenceExceptionOneOrMultiple',
													'aid': this.options.cEvents[i].eventID,
													'effectiveDate' : this.options.cEvents[i].effectiveStart
												});
											}
											return false;
										}
										else
										{
											return true;
										}
								}.bindWithEvent( this, i, event ));
								
							}.bind(this)
						}).send();							
						
						// hide, move and fade in
						this.divPop.setProperty( 'html', // Add spinner "working" img
							'<div class="event_popup_working"><img src="/images/spinner.gif" alt="Spinner" class="working_spinner" /><p class="working_copy">&nbsp;&nbsp;&nbsp;Working...</p></div>'
						);
						this.divPop.setStyles( { opacity:0, display:'block' } );
						this.divPop.position( { x:eventDiv.getPosition().x, y:eventDiv.getPosition().y } );
						this.divPop.fade( 'in' );							
						//this.divPop.getElement('div.divPopupTitle').set( 'html', this.options.cEvents[i].title );
						
					}.bindWithEvent( this, [i, eStart, time, eventDiv] ));
				}
			}
		 },
		showDowRow: function(){
			var tr = new Element('tr',{
				'class':'dowRow'
			});
			var th = new Element('th',{
				'colspan': '7'
			}).inject(tr);
			var ul = new Element('ul').inject(th);
			for (var i = 0; i < 7; i++){ 
				var sundayClass	= ( i == 0 ) ? 'sunday' : '';
				if (this.options.weekStart == 0) {
					new Element('li',{'class':sundayClass}).set('text', this.days[i]).inject(ul);
				}
				else{
					var j = 0;
					if(i == 6){
						j = 0;
					}
					else{
						j = i+1;
					}
					new Element('li').set('text',this.days[j]).inject(ul);
				}
			}
				
			return tr;
		},
		showMonth: function(){
			$(this.options.calContainer).set('html','');
			this.options.view = 'month';
			var table = new Element('table',{
				'cellspacing':'0',
				'class':'mooECal',
				'id':'monthCal'
			});
			var thead = new Element('thead').inject(table);
			var tbody = new Element('tbody').inject(table);
			
			this.showControlsRow(this.months[this.calDate.getMonth()]+' '+this.calDate.getFullYear()).inject(thead);
			
			this.showDowRow().inject(thead);
			
			var calDone = false;
			for (var i = 0; i < 6; i++){
				if(calDone){
					break;
				}
				var tr = new Element('tr',{'class':'monthWeek'}).inject(tbody); // create weeks
				for (var j = 0; j < 7; j++) {
					var day = ((j+1) + (i*7)) - this.startingOffset;
					var sundayClass	= ( j == 0 ) ? ' sunday' : '';
					var td = new Element('td',{'class':'monthDay'+sundayClass,'id':'day'+day}).inject(tr); // create days
					if (day > 0 && day <= this.daysInMonth){
						td.set({
							events: {
								'mouseover': function(){this.addClass('hover')},
								'mouseout': function(){this.removeClass('hover')},
								'dblclick': function(e){
									this.setDate(e.target.retrieve('date'));
									this.showDay();
								}.bind(this)
							}
						});
						new Element('span',{'text':day}).store('date',day).inject(td);
						td.store('date',day);
						td.addEvent('click', function(){
							$$('td.monthDay').each(function(td){td.removeClass('selected')});
							this.addClass('selected');
						});
						td.addEvent('click',function(e){
							this.setDate(e.target.retrieve('date'))
						}.bind(this));
						new Element('div').store('date',day).inject(td);
						if(day == this.calDate.getDate()) //set background color for current day
							td.addClass('selected');
						if(day == this.daysInMonth)
							calDone = true;
					}
					else{
						td.set('html', '&nbsp;'); // IE won't show td borders without something in the cell
					}
				}
			}
			
			this.viewStartDate.setTime(this.calDate.valueOf());
			this.viewStartDate.setDate(1);
			this.viewEndDate.setTime(this.calDate.valueOf());
			this.viewEndDate.setDate(this.daysInMonth);
			this.viewStartDate.startOfDay();
			this.viewEndDate.endOfDay();
			
			table.inject($(this.options.calContainer));
			this.getCalEvents();
			
			// Set the view preference:
			var req = new Request({
				method: 'post',
				url: '/time/services/calendarfeed.php',
				data: { action: 'setView', value: 'month' },
				onRequest: null,
				onComplete: function(response) { 
					// Don't really care that much if it works or not...
					//alert(response);
				}
			}).send();
			
		}, // end of showMonth
		 
		 /**
		  * Overriding mooECal function to ignore refreshing master view if get call is in quick view
		  * @param string _referrer (optional) A referrer string to identify call origination.
		  */
		getCalEvents: function( _referrer ) {
			// Always retreive data (from cache or other)
			this.getMonthlyCalendarData();
			
			// Only render events if ! called from quick view.
			if( _referrer == 'QuickView' ) 
			{
				// Debug:
				//alert('quick view');
				return;
			}
			else
			{
				// Renders the data on the existing calendar dom (only for calendar view)
				this.loadCalEvents();
			}
		},
		
		
		/**
		 * Extending showWeek() to add an ajax call to set the view preference.
		 */
		showWeek: function() {
			this.parent();
			
			// Now the ajax work:
			var req = new Request({
				method: 'post',
				url: '/time/services/calendarfeed.php',
				data: { action: 'setView', value: 'week' },
				onRequest: null,
				onComplete: function(response) { 
					// Don't really care that much if it works or not...
					//alert(response);
				}
			}).send();
		},
		
		/**
		 * Extending showWeek() to add an ajax call to set the view preference.
		 */
		showDay: function() {
			this.parent();
			
			// Now the ajax work:
			var req = new Request({
				method: 'post',
				url: '/time/services/calendarfeed.php',
				data: { action: 'setView', value: 'day' },
				onRequest: null,
				onComplete: function(response) { 
					// Don't really care that much if it works or not...
					//alert(response);
				}
			}).send();
		}
});
