var Calendar = Class.create({	
	
	initialize: function(id, options) {
		this.id  = id;
		this.options = options || { };
		
		this.image = this.options.image || this.id+'__calendar_image';
		this.imagePath = this.options.imagePath || 'calendar.gif';
		
		this.wrapper = this.options.wrapper || this.id+'__calendar_wrapper';
		this.wrapperClass = this.options.wrapperClass || 'calendar_wrapper';
		
		this.container = this.options.container || this.id+'__calendar_container';
		this.containerClass = this.options.containerClass || 'calendar_container';
		
		this.previous = this.options.previous || this.id+'__calendar_previous';
		this.next = this.options.next || this.id+'__calendar_next';
		
		this.month = this.options.month || new Date().getMonth(); // 0-11
	   	this.day = this.options.day || new Date().getDate();
	   	this.year = this.options.year || new Date().getFullYear(); // 4-digit year
	   	
	   	this.renderContainer();
	   	this.positionCalendar();
		
		$(this.wrapper).addClassName(this.wrapperClass);
		$(this.image).observe('click',this.clickCalendar.bind(this));
		$(this.id).observe('click',this.showCalendar.bind(this));
		$(this.id).observe('keyup',this.checkCalendar.bind(this));
	},
	
	hasContainer: function() {
		if($(this.container)){
			return true;
		}
		return false;
	},
	
	renderContainer: function() {
		var container = '<img id="'+this.image+'" src="'+this.imagePath+'" alt="" />';
		container += '<div id="'+this.container+'" class="'+this.containerClass+'" style="display:none;"></div>';
		$(this.wrapper).update(container); 
	},
	
	positionCalendar: function() {
		var top = 17;
		if(Prototype.Browser.IE){
			top = 23;
		}
		
		$(this.container).setStyle({
			position: 'absolute',
			top: top+'px',
			left: '0px'
		});
	},
	
	clickCalendar: function() {	
		if(!this.hasContainer()){
			this.renderContainer();
		}
		
		if(!this.isCalendarVisible()){
			this.showCalendar();
		}
		else {
			this.hideCalendar();
		}
	},
	
	isCalendarVisible: function() {
		return $(this.container).visible();
	},
	
	showCalendar: function() {
		if(!this.isCalendarVisible()){
			this.setDate();
			this.renderCalendar();
			
			$(this.container).show();
		}
	},
	
	hideCalendar: function() {
		$(this.container).hide();
	},
	
	checkCalendar: function() {
		if(this.isCalendarVisible()){
			if(this.isDate()){
				this.setDate();
				this.renderCalendar();
			}
		}
	},
	
	renderCalendar: function() {
		
		var html = '';
		html = '<table cellpadding="0" cellspacing="0"><tr>';
    	html += '<th><a id="'+this.previous+'">&laquo;</a></th>';
    	html += '<th colspan="5" class="month">'+this.getMonthName(this.month)+' '+this.year+'</th>';
		html += '<th><a id="'+this.next+'">&raquo;</a></th>';
		html += '</tr>';
       
       	html += '<tr class="days">';
        var weekDays = new Array('S','M','T','W','T','F','S');
        for (var j=0; j<weekDays.length; j++) {
			html += '<td>'+weekDays[j]+'</td>';
        }
        html += '</tr>';
        
        var daysInMonth = this.getDaysInMonth(this.year,this.month);
        var startDay = this.getFirstDayOfMonth(this.year,this.month);
       
        var numRows = 0;
        var printDate = 1;
        if (startDay != 7) {
            numRows = Math.ceil(((startDay+1)+(daysInMonth))/7); // calculate the number of rows to generate
        }
		
        // calculate number of days before calendar starts
        if (startDay != 7) {
            var noPrintDays = startDay + 1; 
        } else {
            var noPrintDays = 0; // if sunday print right away	
        }
        
		var today = new Date().getDate();
		var thisMonth = new Date().getMonth();
		var thisYear = new Date().getFullYear();
		
		var selectedDate = this.getValue();
		var selectedMonth = selectedDate.month;
		var selectedDay = selectedDate.day;
		var selectedYear = selectedDate.year;
        
        // create calendar rows
        for (var e=0; e<numRows; e++) {
			html += '<tr class="week">';
			
			// create calendar days
            for (var f=0; f<7; f++) {
				
				if ((printDate == selectedDay) 
					 && (this.year == selectedYear) 
					 && (this.month == selectedMonth) 
					 && (noPrintDays == 0)) {
					html += '<td class="selected">';
				}
				
				else if ((printDate == today) 
					 && (this.year == thisYear) 
					 && (this.month == thisMonth) 
					 && (noPrintDays == 0)) {
					html += '<td class="today">';
				} 
				
				else {
                	html += '<td>';
				}
				
                if (noPrintDays == 0) {
					if (printDate <= daysInMonth) {
						html += '<a class="day">'+printDate+'</a>';
					}
                    printDate++;
                }
                html += '</td>';
                if(noPrintDays > 0) noPrintDays--;
            }
            html += '</tr>';
        }
		html += '</table>';
		
		$(this.container).update(html);
		
		this.setupLinks();

	},
	
	setupLinks: function() {
		$(this.previous).observe('click',this.previousMonth.bind(this));  
		$(this.next).observe('click',this.nextMonth.bind(this)); 
		
		var days = $(this.container).getElementsByTagName('a');
		
		// skip previous/next links
		for (var i=2; i<days.length; i++) {
			
			$(days[i]).observe('click',this.clickDay.bind(this,{
				day: $(days[i]).innerHTML
			}));
		}
	},
	
	previousMonth: function() {
		this.month--;
        if (this.month < 0) {
            this.month = 11;
            this.year--;
        }
        this.renderCalendar();
	},
		
	nextMonth: function() {
		this.month++;
        if (this.month > 11) {
            this.month = 0;
            this.year++;
        }
        this.renderCalendar();
	},
	
	clickDay: function(obj) {
		this.setValue(this.month,obj.day,this.year);
	},
	
	setDate: function() {
		var date = this.getValue();
		this.month = date.month;
		this.day = date.day;
		this.year = date.year;
	},
	
	setToday: function() {
		var date = new Date();
		this.setValue(date.getMonth(),date.getDate(),date.getFullYear());
	},
	
	setValue: function(month,day,year) {
		if (this.setValue.arguments.length == 0) {
			var date = this.getValue();
			month = date.month;
			day = date.day;
			year = date.year;
		}
		$(this.id).value = this.formatDate(month,day,year);
		this.hideCalendar();
	},
	
	getValue: function() {
		
		if(this.isDate()){
			var date = new Date($(this.id).value);
		}
		else {
			var date = new Date();
		}
		
		var result = [];
		result.month = date.getMonth();
		result.day = date.getDate();
		result.year = date.getFullYear();
		
		return result;
	},
	
	formatDate: function(month,day,year) {
		
		if(isNaN(month)){
			return '';
		}
		
		month++; // adjust javascript month
	    
	    if (month < 10){
	    	month = '0'+month; // add a zero if less than 10
	    } 
	    
	    if (day < 10) {
	    	day = '0'+day; // add a zero if less than 10
	    }
	    
	    return month+'/'+day+'/'+year;
	},
	
	isDate: function() {
		var date = $(this.id).value;
		return !/Invalid|NaN/.test(new Date(date));
	},
	
	getDaysInMonth: function (year,month) {
	    return 32 - new Date(year, month, 32).getDate();
	},
	
	getFirstDayOfMonth: function (year,month) {
	   return new Date(year, month, 0).getDay();
	},
	
	getMonthName: function(month) {
	    var monthNames = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
	    return monthNames[month];
	}
});