
var miniCal = new function(){
	/*
	 * var show = function(el, handler, options) 
	 * 		el 				=> (required) (string or element reference) The button or html element that is used to call this function  (so that next time you press it, it is loaded with the last date) 
	 * 		handler 		=> (required) (string, element reference, or function reference) The form element whose value you want set to the date chosen OR the function you want to call with the chosen date as it's argument
	 * 		options = {
	 * 			format			=> (optional) (string) The format of the date string using PHP character replacement (see php date() function)
	 * 			m				=> (optional) (int) The default month for the calendar to show
	 * 			y				=> (optional) (int) The default year for the calendar to show
	 * 			default_date	=> (optional) (date or string as 'm d,Y') The default selected date
	 * 			min_date		=> (optional) (date or string as 'm d,Y') The minimum date that the calendar allows you to select
	 * 			max_date		=> (optional) (date or string as 'm d,Y') The maximum date that the calendar allows you to select
	 * 			min_date_of		=> (optional) (element) The button element whose date should be updated when this date is changed
	 * 			dates			=> (optional) (array of dates) The only dates that the calendar allows you to select
	 * 		}
	 * e.g.
	 * <button class="miniCal" onclick="miniCal.show(this,'calendar1',{'format':'Y-m-d','month':10,'year':2000,'default_date':'10,3,2008','min_date':'10 1 2008', 'end_date':new Date(2008,10,30) )">
	 */
	var days = ["S","M","T","W","T","F","S","S"];
	var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
	var cal = function(el, handler,options){
		var today = new Date();
		if(typeof options.min_date == "undefined"){ options.min_date = (new Date()).noTime(); }
		var format = options.format ? options.format : "Y-n-j";
	
		var ext_div = newEl('DIV',{'class':'minical'});
		var int_div = newEl('DIV');
		ext_div.appendChild(int_div);
		
		var default_month = (options.year && options.month) ? new Date(options.year,options.month,1) : (options.default_date ? new Date(options.default_date.getFullYear(),options.default_date.getMonth(),1) : new Date());
		
		var hide = function(){
			if(typeof Animate == "object" && Animate.Tween){
				var tween = Animate.Tween(ext_div.style, 'opacity', 'regularEaseOut', 1, 0,.5,'');
				tween.onMotionFinished = function(){ext_div.style.display = 'none';}
			} else{
				ext_div.style.display = 'none';
			}
			if(options.default_date) default_month = options.default_date;
		}
		var selectDate = function(date){
			el.date = date;
			if(typeof(handler) == "function")
				handler.call(el, date);
			else{
				handler.value = date.format(format);
			}
			options.default_date = date;
			
			if(options.min_date_of && typeof(options.min_date_of) == "object"){
				if(!options.min_date_of.mini_cal){
					options.min_date_of.onclick();
					options.min_date_of.mini_cal.hide();
				}
				options.min_date_of.mini_cal.refreshDate();
			}
		}
		var refreshDate = function(){
			var allowable_dates = (typeof options.dates == "function") ? options.dates() : options.dates;
			if(options.min_date){
				var min_date = getDate(options.min_date, options.min_offset);
				if(allowable_dates && allowable_dates[0] > min_date) min_date =  allowable_dates[0];
				if(!el.date || el.date < min_date){
					default_month = min_date;
					selectDate(min_date);			
				}
			}
			if(allowable_dates){
				if(el.date){
					while(el.date < allowable_dates[allowable_dates.length-1] && !inDates(allowable_dates, el.date)){
						el.date.addDays(1);	
					}
				} else{
					el.date = allowable_dates[0];
				}
				selectDate(el.date);
			}
		}
		var sameDate = function(date1, date2){
			return (date1.getYear() == date2.getYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate());
		}
		var inDates = function(dates, date){
			if(dates.constructor == Array){
				for(var i=0; i<dates.length; i++){
					if(dates[i].constructor != Date) dates[i] = new Date(dates[i]*1000);
					if(sameDate(dates[i], date)) return true;
				}
			}
			return false;
		}
		var getDate = function(el, diff){
			
			if(el && typeof(el) == "object"){
				if(el.constructor == Date){
					date = el;
				}else if(el.onclick){
					if(!el.mini_cal){
						el.onclick();
						el.mini_cal.hide();
					}
					var date = new Date(el.date);
				} else if(el.value){
					var date = new Date(Date.parse(el.value));
				}
				date = date.noTime();
				
				if(diff) date.addDays(diff);
				if(options.dates){
					var allowable_dates = (typeof options.dates == "function") ? options.dates() : options.dates;
					if(allowable_dates){
						while(date < allowable_dates[allowable_dates.length-1] && !inDates(allowable_dates, date)){
							date.addDays(1);	
						}
					}
				}
				

				return date;
			}
		}
		var refresh = function(){
			if(options.dates) var allowable_dates = (typeof options.dates == "function") ? options.dates() : options.dates;
			
			var pos = absPos(el);
			ext_div.style.top = pos.y+"px";
			ext_div.style.left = (pos.x+40)+'px';
			var min_date = getDate(options.min_date, options.min_offset);
			var max_date = getDate(options.max_date, options.max_date_diff);
			y = default_month.getFullYear();
			m = default_month.getMonth();
			var starting_date = new Date(y,m,1-new Date(y,m,1).getDay());
			removeChildren(int_div);
			var table = newEl('TABLE');
			var caption = newEl('CAPTION');
			var prev = newEl('A',{'class':'prev'});
			prev.onclick = function(){default_month = new Date(y,m-1,1); refresh();}
			var next = newEl('A',{'class':'next'});
			next.onclick = function(){default_month = new Date(y,m+1,1); refresh();}
			var month = newEl('SPAN',{'class':'month','innerHTML':months[m]});
			var year = newEl('SPAN',{'class':'year','innerHTML':y});
			appendChildren(caption,[prev,month,year,next]);
			var thead = newEl('THEAD');
			var tr = newEl('TR');
			
			for(var i=0,th;i<7;i++){
				th = newEl('TH',{'innerHTML':days[i]});
				tr.appendChild(th);
			}
			thead.appendChild(tr);
			var tbody = newEl('TBODY');
			var date = starting_date;
			for(var w=0;w<6;w++){
				tr = newEl('TR');
				for(var d=0;d<7;d++){
					td = newEl('TD');
					if(date.getMonth() == m && date.getFullYear() == y){
						if((min_date && date < min_date) || (max_date && date > max_date) || (allowable_dates && !inDates(allowable_dates, date))){
							td.className = 'invalid';
							td.innerHTML = date.getDate();
						} else{
							a = newEl('A',{'innerHTML':date.getDate()});
							new function(a,date){a.onclick = function(){selectDate(date);hide()}}(a,new Date(date));
							td.appendChild(a);
							if(options.default_date && sameDate(date, options.default_date)){
								td.className = 'active';
							}
						}
					} else{
						td.innerHTML = date.getDate();
					}
					
					tr.appendChild(td);
					date.setDate(date.getDate()+1);
				}
				tbody.appendChild(tr);
			}
			appendChildren(table,[caption,thead,tbody]);
			int_div.appendChild(table);
		}
		this.hide = hide;
		this.refresh = refresh;
		this.refreshDate = refreshDate;
		this.selectDate = selectDate;
		
		this.div = ext_div;
		
	}
	var show = function(el,handler,options){
		if(!el.mini_cal){ // FIRST TIME..
			if(typeof options != "object") options = {};
			el = typeof(el) == "string" ? document.getElementById(el) : el;
			handler = typeof(handler) == "string" ? document.getElementById(handler) : handler;
			if(options.default_date && typeof(options.default_date) == "string"){
				if(Date.parse(options.default_date)) options.default_date = new Date(Date.parse(options.default_date));
			}
			if(options.default_date && options.default_date.constructor != Date) options.default_date = false;
			if(!options.default_date && typeof(handler) == "object" && handler.value){
				var ms;
				if(ms = Date.parse(handler.value))	options.default_date = new Date(ms);
			}
			
			if(options.min_date && typeof(options.min_date) == "string"){
				if(d = Date.parse(options.min_date)) options.min_date = new Date(d);
				else if(parts = /(.+)(\+\+|--)([0-9]+$)/.exec(options.min_date)){
					options.min_date = document.getElementById(parts[1]);
					options.min_offset = parseInt(parts[2].charAt(0)+parts[3]);
				} else
					options.min_date = document.getElementById(options.min_date);
			}
			if(options.max_date && typeof(options.max_date) == "string"){
				if(d = Date.parse(options.max_date)) options.max_date = new Date(d);
				else options.max_date = document.getElementById(options.max_date);
			}
			if(options.min_date_of && typeof(options.min_date_of) == "string") options.min_date_of = $(options.min_date_of);
			var mini_cal = new cal(el,handler,options);
			mini_cal.options = options;
			document.body.appendChild(mini_cal.div);
			makeDraggable(mini_cal.div);
			disableSelections(mini_cal.div);
			el.mini_cal = mini_cal;
			if(options.default_date) mini_cal.selectDate(options.default_date);
		}
		el.mini_cal.div.style.display = 'block';
		el.mini_cal.refresh();
		if(typeof Animate =="object" && Animate.Tween){
			var tween = Animate.Tween(el.mini_cal.div.style, 'opacity', 'regularEaseOut', 0, 1,1,'');
		}
		addOnBlur(el.mini_cal.div,function(){el.mini_cal.hide();});
		return true;
	}
	this.show = show;
}


// Simulates PHP's date function
Date.prototype.format = function(format) {
	var shortMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
	var longMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
	var shortDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
	var longDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
	var token = /d|D|j|l|N|S|w|z|W|F|m|M|n|t|L|o|Y|y|a|A|B|g|G|h|H|i|s|e|I|O|T|Z|c|r|U/g;
	var flags = {
		d:  (this.getDate() < 10 ? '0' : '') + this.getDate(),
		D:  shortDays[this.getDay()],
		j:  this.getDate(),
		l:  longDays[this.getDay()],
		N:  this.getDay() + 1,
		S:  (this.getDate() % 10 == 1 && this.getDate() != 11 ? 'st' : (this.getDate() % 10 == 2 && this.getDate() != 12 ? 'nd' : (this.getDate() % 10 == 3 && this.getDate() != 13 ? 'rd' : 'th'))),
		w:  this.getDay(),
		z:  Math.floor((new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime()-new Date(this.getFullYear(),1,1).getTime())/86400000)+1,
		// Week
		W:  Math.floor((new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime()-new Date(this.getFullYear(),1,1).getTime())/604800000)+1,
		// Month
		F:  longMonths[this.getMonth()],
		m:  (this.getMonth() < 9 ? '0' : '') + (this.getMonth() + 1),
		M:  shortMonths[this.getMonth()],
		n:  this.getMonth() + 1,
		t:  new Date(this.getFullYear(), this.getMonth()+1, 0).getDate(),
		// Year
		L:  (!(this.getFullYear() % 4) && (this.getFullYear() % 100) || !(this.getFullYear() % 400))?1:0,
		o:  "Not Supported",
		Y:  this.getFullYear(),
		y:  ('' + this.getFullYear()).substr(2),
		// Time
		a:  this.getHours() < 12 ? 'am' : 'pm',
		A:  this.getHours() < 12 ? 'AM' : 'PM',
		B:  Math.round(((this.getUTCHours()*3600)+(this.getUTCMinutes()*60)+this.getUTCSeconds())/86.4),
		g:  this.getHours() == 0 ? 12 : (this.getHours() > 12 ? this.getHours() - 12 : this.getHours()),
		G:  this.getHours(),
		h:  (this.getHours() < 10 || (12 < this.getHours() < 22) ? '0' : '') + (this.getHours() < 10 ? this.getHours() + 1 : this.getHours() - 12),
		H:  (this.getHours() < 10 ? '0' : '') + this.getHours(),
		i:  (this.getMinutes() < 10 ? '0' : '') + this.getMinutes(),
		s:  (this.getSeconds() < 10 ? '0' : '') + this.getSeconds(),
		// Timezone
		e:  "Not Yet Supported",
		I:  "Not Supported",
		O:  (this.getTimezoneOffset() < 0 ? '-' : '+') + (this.getTimezoneOffset() / 60 < 10 ? '0' : '') + (this.getTimezoneOffset() / 60) + '00',
		T:  "Not Yet Supported",
		Z:  this.getTimezoneOffset() * 60,
		// Full Date/Time
		c:  "Not Yet Supported",
		r:  this.toString(),
		U:  this.getTime() / 1000
	}
	return format.replace(token, function ($0) {
		return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
	});
};
Date.prototype.addDays = function(days) {
	this.setDate(this.getDate()+days);
} 
Date.prototype.noTime = function() {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate());
}
Date.oldparse = Date.parse;
Date.parse = function(d){
	if(d && typeof(d) == "string"){
		var m;
		if(m = d.match(/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/)){
			if(m[2] > 0 && m[2] <= 12 && m[3] > 0 && m[3] <= 31)
				return new Date(m[1], m[2]-1, m[3]);
		}
		return Date.oldparse(d);
	}
}
