/* 
	August 2009 
	Alex Duff for barbduff.com
	
	If you are crazy enough to use this script, be my guest, but please attribute.
	And also visit www.relcad.com for some of my "challenging" music.
	Cheers!
	
	-Alex


*/
	

	
		
/********** Begin Calendar madness ***************************/


 //Globals
     var br = "<br />"
     var rawDate = 0;
      
      var _loDate = new Date();
      var _currentUDate = convertToUTC(_loDate);
      var _currentPacDate = convertToPacTime(_currentUDate);
      var eventCount = 0;
      var days = new Object();

  //end Globals
  
  /*data objects - List objects shall be initialized on the page so browser does not cache
	date sensitive info */
  
      function day(oDate){
		this.date = oDate;
		this.eventIDs = "";
		this.sortedEventIDs = "";   
      }
      
      
      function event(month, day, year, hour, minute, dayOfWeek, bRecurring, begins, ends, eventName){
        
        this.index;
        this.recurring = bRecurring;
        this.dayOfWeek = dayOfWeek;
        this.dispHour = hour;
        this.dispMinute = minute;
        this.exceptionIDs = "";
        this.eventName = eventName;


        if(month.toString().length > 0){
          this.localDate = new Date(month + ' ' + day + ', ' + year + ' ' + hour + ":" + minute + ':00 GMT-0800');
          
          
        }else{
		  // Just initialize date with static, plus the time info that was passed in - we will update the pacDate later when looping through weeks
		  this.localDate  = new Date('Aug 01, 2009 ' + hour + ':' + minute + ':00 GMT-0800');
        
        }
        
        this.UDate = convertToUTC(this.localDate);
		this.pacDate = convertToPacTime(this.UDate);
        this.isNext = false;
        if(bRecurring){
			this.beginDate = convertToPacTime(convertToUTC(new Date(begins + ' 00:00:00 GMT-0800')));
			this.endDate = convertToPacTime(convertToUTC(new Date(ends + ' 00:00:00 GMT-0800')));
        }
      }
          
      function eventException(eventID, date, freeText, removeClass){
		this.eventID = eventID;
		this.date = convertToPacTime(convertToUTC(new Date(date + ' 00:00:00 GMT-0800')));
		this.freeText = freeText;
		this.removeClass = removeClass;
      
      }
      
 // end data objects    
 


 // page init
      
      function initializeTheWeek(weeksAhead){
      
		var currentDay = _currentPacDate.getDay();
		var weekIncr = (weeksAhead * 7);
		var currentDate = _currentPacDate.getDate();
		var incr = 0;
		var oTempDays = new Object();
			
		for(var i = 0; i<=6; i++){
		
			oTempDays[i] = new day(new Date(_currentPacDate));
					
			if(currentDay > i){
			 incr = currentDay - i;
			 oTempDays[i].date.setDate(currentDate - incr + weekIncr);
			
			}else if(currentDay < i){
			
			 incr++;
			 oTempDays[i].date.setDate(currentDate + incr + weekIncr);		
			}else{
			  oTempDays[i].date.setDate(currentDate + weekIncr);
			  incr = 0;
			}
		}
		initializeEventsForWeek(oTempDays);
		return oTempDays;
		
      }
      
      function initializeEventsForWeek(oDays){
		if(eventCount == 0){
			initializeEventCount();
		}
      
		// loop thru days
		for(var i = 0; i <= 6; i++){
		 //loop thru events
		 for(var x = 0; x < eventCount; x++){
		 
			if(myEvents[x].recurring){
				if(oDays[i].date.toString().indexOf(myEvents[x].dayOfWeek) != -1){
					myEvents[x].pacDate = new Date(oDays[i].date);
					myEvents[x].pacDate.setHours(myEvents[x].dispHour);
					myEvents[x].pacDate.setMinutes(myEvents[x].dispMinute);
					myEvents[x].UDate = convertToUTC(myEvents[x].pacDate);
					if((myEvents[x].pacDate >= myEvents[x].beginDate) && (myEvents[x].pacDate <= myEvents[x].endDate)){
						oDays[i].eventIDs += x + "*";
					}
						// get exceptions for event
						myEvents[x].exceptionIDs = "";
						for(var e in exceptions){
							if(exceptions[e].eventID == x){
								if(exceptions[e].date.toDateString() == myEvents[x].pacDate.toDateString()){
									myEvents[x].exceptionIDs += e + "*";
								} 
							}
						}
						
						if(myEvents[x].exceptionIDs.length > 0){
							myEvents[x].exceptionIDs = myEvents[x].exceptionIDs.substring(0, myEvents[x].exceptionIDs.lastIndexOf('*'));
						}
				
				
				}
			}else{
				if(myEvents[x].pacDate.toDateString() == oDays[i].date.toDateString()){
					oDays[i].eventIDs += x + "*";
				}
			}
			
		} 
		 sortDayEvents(oDays, i);
		}
      }
      
      /* sorts events in a day by time */
      function sortDayEvents(oDays, dayIndex){
		
		var sortedString = "";
		
		if (oDays[dayIndex].eventIDs.length == 0){
			oDays[dayIndex].sortedEventIDs = "";
		
		}else if(oDays[dayIndex].eventIDs.length == 2){
			oDays[dayIndex].sortedEventIDs = oDays[dayIndex].eventIDs.substring(0,1); 
		}else{
		 
			oDays[dayIndex].eventIDs = oDays[dayIndex].eventIDs.substring(0, oDays[dayIndex].eventIDs.lastIndexOf('*')); 
			arrEvents = oDays[dayIndex].eventIDs.split('*');
			arrEvents.sort(compareEventTimes);
			
			for(i = 0; i < arrEvents.length; i++){
				sortedString += arrEvents[i];
				if(i != arrEvents.length - 1){
					sortedString += "*";
				}
				
			} 
			
			oDays[dayIndex].sortedEventIDs = sortedString;
		}
      }
      
      /* comparison method for arrEvents.sort*/
      function compareEventTimes(indexA, indexB){

		if(myEvents[indexA].pacDate.getHours() < myEvents[indexB].pacDate.getHours()){
			return -1;
		}else if(myEvents[indexA].pacDate.getHours() > myEvents[indexB].pacDate.getHours()){
			return 1;
		}else{
			return 0;
		}
      
      }
      
      function initializeEventCount(){
		for(var E in myEvents){
			
			myEvents[E].index = eventCount;
			eventCount++;
			
		}
      }
      
      
 //end page init     

 //UI Functions//     
     
      // this populates the calendar list
      function outputCalendar(){
		var oCal = document.getElementById('calendarContainer');
		var oListItem = null;
		var oDay = null;
		var dayIndex = 0;
		var strHTML = "";
		var arrDayEvents = null;
		var arrExceptions = null;
		var cancelEvent = false;
		var oEvent = null;
		var pastAM = false;
		var pastAfternoon = false;
		
		for(var Li in oCal.childNodes){
			// its a new day
			pastAM = false;
			pastAfternoon = false;
			strHTML = "";
			
			
			if(oCal.childNodes[Li].nodeType == 1){
				oListItem = oCal.childNodes[Li];
				oDay = days[dayIndex];
				strHTML += '<table border="0" width="100%" cellpadding="0" bgcolor="white" cellspacing="1px"><tr><th colspan="2">';
				//wRITE THE DATE
				strHTML +=  longDay(oDay.date.getDay()) + br + longMonth(oDay.date.getMonth()) + ' ' + oDay.date.getDate();
				strHTML += '</th></tr>'
				// see if this day has events
				if(oDay.sortedEventIDs.length > 0){
					arrDayEvents = oDay.sortedEventIDs.split('*');
					strHTML += '<tr><td width="0"><img src="calendarsupport/1x1.gif" height="32" width="1" /></td><td valign="top">';
					//it does go thru events
					for(var i = 0; i < arrDayEvents.length; i++){
						cancelEvent = false;
						oEvent = myEvents[arrDayEvents[i]];
						//look for exceptions
						if(oEvent.exceptionIDs.length > 0){
							arrExceptions = oEvent.exceptionIDs.split('*');
							
							for(var n = 0; n < arrExceptions.length; n++){
								cancelEvent = exceptions[arrExceptions[n]].removeClass;
								if(cancelEvent){
									break;
								}
							}					
						}
	
						//alert(oEvent.pacDate.getHours());
						if(oEvent.pacDate.getHours() >= 12 && !pastAM){
						//	alert('writing end / begin cell')
							strHTML += '</td></tr><tr><td width="0"><img src="calendarsupport/1x1.gif" height="32" width="1" /></td><td valign="top">';	
							pastAM = true;
						}
						if(oEvent.pacDate.getHours() >= 17 && !pastAfternoon){
						//	alert('writing end / begin cell')
							strHTML += '</td></tr><tr><td width="0"><img src="calendarsupport/1x1.gif" height="32" width="1" /></td><td valign="top">';	
							pastAfternoon = true;
						}
							
						if(!cancelEvent){
							strHTML +=  politeTime(oEvent.pacDate.getHours(), 
													oEvent.pacDate.getMinutes());

							if(oEvent.exceptionIDs.length > 0){
								for(var y = 0; y < arrExceptions.length; y++){		
									strHTML += ' - ' + exceptions[arrExceptions[y]].freeText + '<br />';
								}
							}else{
								strHTML += ' - ' + oEvent.eventName + '<br />'; 
							}
						}else{
							//strHTML += "<tr><td>";
							for(var n=0; n < arrExceptions.length; n++){
								if(exceptions[arrExceptions[n]].freeText){
									strHTML += exceptions[arrExceptions[n]].freeText + br;
								} 
							}
						}
					}
				}
				if(strHTML.lastIndexOf("</tr>") != (strHTML.length - 5)){
				//	alert('lower end td/tr');
					strHTML += "</td></tr>";
				}
				strHTML += '</table>'
		
				oListItem.innerHTML = strHTML;
			//	alert(strHTML);
				dayIndex++;
			}
		}
      }
      
      function getLocationID(eventID){
		return myEvents[eventID].locationName;
      
      }
      
      
      
      
      var theWeek = 0;
      /*called from href and page load to initialize the calendar */
      
      function moveWeek(direction){

		if((document.forms[0].woffset.value > 0) && (document.forms[0].woffset.value != theWeek)){
			theWeek = Math.abs(document.forms[0].woffset.value) + 1;
		}
		
			
		if(direction == 'fwd'){
			theWeek++;
			days = initializeTheWeek(theWeek);
		
		}else{
			if(theWeek > 0){
				theWeek--;
				days = initializeTheWeek(theWeek);
			}else{
				days = initializeTheWeek(0);
			}
		}
		
		//save week offset state
		document.forms[0].woffset.value = theWeek;

		outputCalendar();
		oAnc = document.getElementById('prev');
		if(theWeek == 0){
			oAnc.style.color = "#cccccc";
			oAnc.style.cursor = "default";
		}else{
			oAnc.style.color = "";
			oAnc.style.cursor = "";
		}
      
		/*
		if(document.forms[0].eventID.value.length > 0){
			displayEvent(document.forms[0].eventID.value, document.forms[0].eventDate.value);
		}
		*/
      
      }
      
      function displayEventFromIndex(eventIndex, eventDate){
		
		var eventID = 0;
		
		for(var i = 0; i < eventCount; i++){
			if(myEvents[i].index == eventIndex){
				eventID = i;
				break;
			} 
		}
		
		displayEvent(eventID, eventDate);
		
      
      }
      
      function hideEvents(){
		var oDiv = document.getElementById('eventDisplay');
		oDiv.className = "hidden"; 
		document.forms[0].eventID.value="";
		document.forms[0].eventDate.value="";
      }
      
     
      
    // this needs to be called after all the initializers - but also kind of needs to do it's own thing e.g. non-destructive advancing the week offfset and week
    function getNextClass(){
    
		var bNextClassFound = false;
		var lDays = null;
		var weekOffset = 0;
		var arrDayEvents = null;
		var oNextEvent = null;
		var removeClassExceptionFound = false;
		var arrExceptions = null;
		
		while (!bNextClassFound){
				
			lDays = initializeTheWeek(weekOffset);
			
			//loop thru days
			for(var d in lDays){
				//loop thru day events
				if(lDays[d].sortedEventIDs.length > 0){
					arrDayEvents = lDays[d].sortedEventIDs.split('*');
					for(var i = 0; i < arrDayEvents.length; i++){
						removeClassExceptionFound = false;
						if(myEvents[arrDayEvents[i]].pacDate > _currentPacDate){
							oNextEvent = myEvents[arrDayEvents[i]];
							if(oNextEvent.exceptionIDs.length > 0){
								arrExceptions = oNextEvent.exceptionIDs.split('*');
								for(var n = 0; n < arrExceptions.length; n++){
									if(exceptions[arrExceptions[n]].removeClass){
										removeClassExceptionFound = true;
									}
								}
							}
							if(!removeClassExceptionFound){
								bNextClassFound = true;
								break;
							}
						}				
					}
				}
					if(bNextClassFound){
						break;
					}							
			}
			
			if(weekOffset == 2){
				bNextClassFound = true;
			}
			weekOffset ++; 
		}
		
		return oNextEvent;
    }
    
    
    
    function displayNextClass(){
		var oDiv = document.getElementById('nextClass');
		var oEvent = getNextClass();
		var strHTML = '<p>Our next class is '; 
	//	strHTML += '<a href="javascript:displayEventFromIndex(' + oEvent.index + ', \'' + oEvent.pacDate.toDateString() + '\');">';
		strHTML +=  '<b>' + niceDate(oEvent.pacDate, 'mm/dd/yyyy') + ' ' + politeTime(oEvent.pacDate.getHours(), oEvent.pacDate.getMinutes()) + '</b>' ;
	//	strHTML += '</a>';
	//	strHTML += ' at ' + locations[oEvent.locationName].nameString + '</p>';
		strHTML += ' with <b>' + oEvent.eventName + '</b>!</p>';
		
		oDiv.innerHTML = strHTML;
    }
      
      
 // end UI Functions
      
// format functions
	
	   function politeTime(hour, minutes){
      
		var retVal = hour;
      
		  if(hour > 12){
			retVal =  hour - 12;
		  }else if(hour == 0){
			retVal = "12";
		  }
		   
		  
		  if(minutes != 0){
			retVal += ":";
			if(minutes.toString().length == 1){
				retVal += "0";
			}
			
			retVal += minutes;
		  }
		  
		  if(hour > 11){
			retVal += "pm";
		  }else{
			retVal += "am";
		   }
      
		return retVal;
      
      }
      
      //formats are mm/dd/yy or long 
      function niceDate(date, format){
      
		var retVal = '';
		
			
		var mo = date.getMonth();
		var dayNo = date.getDate();
		var dayName = date.getDay();
		var year = date.getFullYear();
		
		if(format == 'mm/dd/yyyy'){
			retVal = mo + 1 + '/' + dayNo + '/' + year;
		}else if(format == 'long'){
			retVal = longDay(dayName) + ' ' + longMonth(mo) + ' ' + dayNo + ', ' + year; 
		}
      
      
		return retVal; 

      }
            
      function longMonth(shortMonth){
		
		switch(shortMonth){
			case 'Jan':
				return 'January';
				break;
			case 0:
				return 'January';
				break;
			case 'Feb':
				return 'February';
				break;
			case 1:
				return 'February';
				break;
			case 'Mar':
				return 'March';
				break;
			case 2:
				return 'March';
				break;
			case 'Apr':
				return 'April';
				break;
			case 3:
				return 'April';
				break;
			case 'May':
				return 'May';
				break;
			case 4:
				return 'May';
				break;
			case 'Jun':
				return 'June';
				break;
			case 5:
				return 'June';
				break;
			case 'Jul':
				return 'July';
				break;
			case 6:
				return 'July';
				break;
			case 'Aug':
				return 'August';
				break;
			case 7:
				return 'August';
				break;
			case 'Sep':
				return 'September';
				break;
			case 8:
				return 'September';
				break;
			case 'Oct':
				return 'October';
				break;
			case 9:
				return 'October';
				break;
			case 'Nov':
				return 'November';
				break;
			case 10:
				return 'November';
				break;
			case 'Dec':
				return 'December';
				break;
			case 11:
				return 'December';
				break;
		}
      
      }
      
      function longDay(shortDay){
		switch(shortDay){
			case 'Sun':
				return 'Sunday';
				break;
			case 0:
				return 'Sunday';
				break;
			case 'Mon':
				return 'Monday';
				break;
			case 1:
				return 'Monday';
				break;
			case 'Tue':
				return 'Tuesday';
				break;
			case 2:
				return 'Tuesday';
				break;
			case 'Wed':
				return 'Wednesday';
				break;
			case 3:
				return 'Wednesday';
				break;
			case 'Thu':
				return 'Thursday';
				break;
			case 4:
				return 'Thursday';
				break;
			case 'Fri':
				return 'Friday';
				break;
			case 5:
				return 'Friday';
				break;
			case 'Sat':
				return 'Saturday';
				break;
			case 6:
				return 'Saturday';
				break;
		
		}
      
      }
      
	//end format functions

    //date helpers//
      function convertToPacTime(UTCDate){
		var retVal = new Date(UTCDate);
		var hourOffset = 7;
			
		retVal.setHours(getPacificHour(retVal.getHours() - hourOffset));
		retVal.setDate(getPacificDay(retVal.getDate()));
		
		return retVal;
      
      }
      
      function convertToUTC(theDate){
		
        return new Date(theDate.getUTCFullYear(), theDate.getUTCMonth(), theDate.getUTCDate(),
                            theDate.getUTCHours(), theDate.getUTCMinutes(), theDate.getUTCSeconds()
                            );
      
      }
      
      function getPacificHour(i){
       rawDate = i;
        if(i < 0){
          i = 24 + i;
        }
        
        return i;
      }
      
      function getPacificDay(i){
        if(rawDate < 0){
          i = i - 1;
        }
        return i;
      
      }
      
    
    //end date helpers//
    

    
  


