var planningCalculator = {};
// one day in milliseconds
planningCalculator.one_day = 1000*60*60*24;
// the google calendar service object
planningCalculator.calSvc = {
	url: "http://www.google.com/calendar/feeds/greenerprinter.com_606ip1m53ocbrvr2cttv51h96k%40group.calendar.google.com/public/full",
	init: function () {
		// construct service transport
		this.svc = new google.gdata.calendar.CalendarService('turnaroundCalc');
		// construct query object
		this.query = new google.gdata.calendar.CalendarEventQuery(this.url);
		this.query.setSingleEvents(true);
		this.query.setOrderBy("starttime");
		this.query.setSortOrder("ascending");
		// construct the event cache object
		this.events = function() {
			var eventCache = {};
			return {
				clear: function() {
					while (eventCache.length > 0) eventCache.pop();
				},
				set: function(month, year, events) {
					eventCache[month + "-" + year] = events;
				},
				get: function(month, year) {
					return eventCache[month + "-" + year];
				}
			};
		}();
	},
	boundQuery: function(startDt, endDt) { // bound the start and end time of the calendar query
		var queryStart = new google.gdata.DateTime(startDt, true);
		var queryEnd = new google.gdata.DateTime(endDt, true);
		this.query.setMinimumStartTime(queryStart);
		this.query.setMaximumStartTime(queryEnd);
	},
	queryAndExecute: function(startDt, endDt, continuation, errorHandler) { // bound the query and then execute with the given continuation
		if (!errorHandler) errorHandler = $.noop;
		this.boundQuery(startDt, endDt);
		this.svc.getEventsFeed(this.query, continuation, errorHandler);
	}
};
// called to populate events
planningCalculator.popEvents = function(month, year, postcallback) {
	var eventsObj = this.calSvc.events;
	if (typeof eventsObj.get(month, year) == "undefined") {
		//this.ui.write.title("retrieving events...");
		this.ui.write.loader("retrieving events...");
		this.ajaxLoader.on();
		var start = new Date(year, month, 1);
		var end = new Date(year, month+1, 1);
		// create the callback
		var regcallback = this.calEvtParserGen(month, year);
		var callback = (!postcallback ? regcallback : function (root) { // need to intercept
			regcallback(root);
			postcallback();
		});
		this.calSvc.queryAndExecute(start, end, callback);
	}
};
planningCalculator.calEvtParserGen = function (month, year) {
	var that = this;
	var eventDts = [];
	return function (root) {
		// Obtain the array of matched CalendarEventEntry
		var eventEntries = root.feed.getEntries();
	
		// If there is matches for the date query
		for (var i = 0; i < eventEntries.length; i++) {
			var event = eventEntries[i];
			var startTime = event.getTimes()[0].startTime;
			if (startTime) {
				var startTimeParts = startTime.split("-");
				var eventDt = new Date(startTimeParts[0], +startTimeParts[1]-1, startTimeParts[2]);
				if (eventDts.length > 0) {
					var lastEvent = eventDts[eventDts.length-1];
					if (lastEvent.start - eventDt === 0) continue; // duplicate, skip
				}
				eventDts.push({ title: "closed", start: eventDt });
			}
		}
		that.calSvc.events.set(month, year, eventDts);
		that.transitCal.fullCalendar('addEventSource', eventDts);
		that.ui.clear.title();
		that.ajaxLoader.off();
	};
};

// a cache of ups ground transit days, keyed by zip
planningCalculator.transit = function() {
	var transitCache = {};
	return {
		clear: function() {
			while (transitCache.length > 0) transitCache.pop();
		},
		set: function(zip, transitObj) {
			transitCache[zip] = transitObj;
		},
		get: function(zip) {
			return transitCache[zip];
		}
	};
}();
// used to get extra transit time info
planningCalculator.getGroundTime = function(zip, continuation) {
	zip = $.trim(zip); // normalize just in case
	var transitObj = this.transit.get(zip);
	var that = this;
	var local = -1, gnd = -1;
	if (!transitObj) {
		$.ajax({
			url: '/grp/upsGroundTime.do', 
			data: {zip: zip}, 
			success: function (data) {
				transitObj = data;
				local = transitObj["local"]; // number of days for local
				gnd = transitObj["ground"]; // number of days for ups ground
				if (gnd >= 0) {
					var start = new Date();
					var end = new Date(start.getTime() + (gnd * that.one_day));
					// consult the google calendar service to normalize ground shipping time
					var callback = function(root) {
						var eventEntries = root.feed.getEntries();
						// subtract non-working days
						transitObj["ground"] = gnd - eventEntries.length;
						that.transit.set(zip, transitObj);
						continuation(transitObj);
					};
					that.calSvc.queryAndExecute(start, end, callback, errorback);
				} else {
					errorback();
				}
			}, 
			error: function(xhr, textStatus, errorThown) {
				errorback();
			},
			dataType: "json"});
	} else { // already cached, we can just use it
		continuation(transitObj);
	}
	// calendar service error, treat ground as being unusable
	var errorback = function(error) {
		transitObj = { ground: gnd, local: local };
		that.transit.set(zip, transitObj);
		continuation(transitObj);
	};
};

// turnaround dates
planningCalculator.turnarounds = [];
planningCalculator.turnNames = {};		
// initialize the turnaround options
planningCalculator.initTurnarounds = function () {
	var turnaroundRx = /^([0-9]+)[^0-9]*$/;
	var turnarounds = $(":input[name='turnaround']");
	var turnaroundVals = this.turnarounds;
	while (turnaroundVals.length > 0) turnaroundVals.pop();
	turnarounds.each(function () {
		var thisRx = turnaroundRx.exec(this.value);
		if (thisRx) {
			turnaroundVals.push(+thisRx[1]);								
		}
	});
	
	turnaroundVals = turnaroundVals.sort();
	for (var i = 0; i < turnaroundVals.length; i++) {
		var day = turnaroundVals[i];
		var append = " Business Days";
		var prepend = "Standard ";
		if (i == 0) {
			prepend = "Rush ";
		} else if (i == turnaroundVals.length - 1) {
			prepend = "Economy ";
		}
		this.turnNames[day] = prepend + day + append;
	}
};

// a set of pre-defined hex color values
planningCalculator.color = {
	proof: '#000C8F',
	print: '#599907',
	ship: '#BF4300',
	arrive: '#4F0000',
	deadline: '#105F00'
};
// functions for displaying
planningCalculator.ui = function () {
	var titleJQ, basicJQ, detailJQ, loaderJQ;
	var slid, sliderJQ;
	var choices = { turnaround: "-1" };
	// control turnaround click behavior
	var turnaroundChooser;
	var turnarounds;
	var estiForm;
	var that = {
		init: function () {
			titleJQ = $("#statusMsg");
			basicJQ = $("#eventMsg #basicMsg");
			detailJQ = $("#eventMsg #detailMsg");
			afterJQ = $("#afterMsg");
			//sliderJQ = $("#eventSlider");
			slid = true;
			loaderJQ = $("#loaderMsg");
			// init turnaround stuff
			turnaroundChooser = $("#eventFooter").children("a");
			turnarounds = $(":input[name='turnaround']");
			estiForm = $("form[name='estiForm']");
			turnaroundChooser.click(function (e) {
				turnarounds.each(function () {
					if (this.value.indexOf(choices.turnaround) > -1) {
						if (this.click) this.click(); // weird jquery not triggering default?
						else $(this).click();
					}
				});
				
				// inject some information that can carry over into shipping
				var $toInject = estiForm.find(":input[name='jobPlan.shipType']");
				if (!$toInject.length) {
					$toInject = $("<input type='hidden' name='jobPlan.shipType' value=''/>");
					estiForm.append($toInject);
				}
				$toInject.val(choices.shipping.method);
				
				if (choices.zip) {
					$toInject = estiForm.find(":input[name='jobPlan.shipZip']");
					if (!$toInject.length) {
						$toInject = $("<input type='hidden' name='jobPlan.shipZip' value=''/>");
						estiForm.append($toInject);
					}
					$toInject.val(choices.zip);
				}
				
				var $toInject = estiForm.find(":input[name='jobPlan.deadline']");
				if (!$toInject.length) {
					$toInject = $("<input type='hidden' name='jobPlan.deadline' value=''/>");
					estiForm.append($toInject);
				}
				$toInject.val(choices.deadline);
			}).hide();
		},
		slide: function(msg, elem) {
			elem.html(msg);
			if (!slid) {
				slid = true;
				sliderJQ.slideDown('fast');
			}
		},
		clear: {
			title: function () {
				that.write.loader("&nbsp;");
				titleJQ.fadeOut('slow');
			},
			messages: function () {
				that.write.basic("");
				that.write.detail("");
				that.write.after("");
			}
		},
		write: {
			title: function (msg) {
				that.slide(msg, titleJQ);
			},
			basic: function (msg) {
				that.slide(msg, basicJQ);
			},
			detail: function (msg) {
				that.slide(msg, detailJQ);
			},
			after: function (msg) {
				that.slide(msg, afterJQ);
			},
			loader: function (msg) {
				loaderJQ.html(msg);
			}		
		},
		read: {
			title: function () {
				return titleJQ.html() || "";
			},
			basic: function () {
				return basicJQ.html() || "";
			},
			detail: function () {
				return detailJQ.html() || "";
			},
			after: function () {
				return afterJQ.html() || "";
			},
			loader: function () {
				return loaderJQ.html() || "";
			}		
		},
		append: {
			title: function (msg) {
				that.write.title(that.read.title() + msg);
			},
			basic: function (msg) {
				that.write.basic(that.read.basic() + msg);
			},
			detail: function (msg) {
				that.write.detail(that.read.detail() + msg);
			},
			after: function (msg) {
				that.write.after(that.read.after() + msg);
			},
			loader: function (msg) {
				that.write.loader(that.read.loader() + msg);
			}
		},
		toggleTurnaround: function(turnaround, shipping, deadline, zip) {
			turnaroundChooser.show();
			choices.turnaround = turnaround;
			choices.shipping = shipping;
			choices.deadline = deadline;
			choices.zip = zip;
			turnaroundChooser.children("span").html("Select " + turnaround + " day turnaround");
		}
	};
	return that;
}();
// used to format the dates
planningCalculator.formatDate = function(dt) {
	var retstr = "";
	switch (dt.getDay()) {
		case 0: retstr += "Sunday, "; break;
		case 1: retstr += "Monday, "; break;
		case 2: retstr += "Tuesday, "; break;
		case 3: retstr += "Wednesday, "; break;
		case 4: retstr += "Thursday, "; break;
		case 5: retstr += "Friday, "; break;
		case 6: retstr += "Saturday, "; break;
	}
	retstr += (dt.getMonth() + 1) + "/" + dt.getDate();
	return retstr;
};	
// remember the day that was last clicked
planningCalculator.lastDayPicked = null;
// lock to prevent multiple events being dispatched
planningCalculator.dayClickSyncOn = false;
// makes an ajax call to retrieve the ups ground cache time, if necessary
// calls the given continuation on success

// called to initialize things
planningCalculator.init = function () {
	this.calSvc.init();
	this.ui.init();
	this.initTurnarounds();
	this.initShipMethodEvents();
	// the element we will attach the calendar to
	var transitCal = this.transitCal = $('#transitCal');
	if (transitCal.html() === "") {				
		var today = new Date();				
		var cutoff = new Date(today);
		cutoff.setHours(17);
		cutoff.setMinutes(0);
		cutoff.setSeconds(0);
		cutoff.setMilliseconds(0);

		var that = this;

		// returns a filtering function to see if the event in question is between the two dates
		var genDateFilter = function(startDt, endDt) {
			var startDtStr = startDt.toDateString();
			var endDtStr = endDt.toDateString();
			return function (fullCalEvt) {
				var evtDt = fullCalEvt.start;
				var evtDtStr = evtDt.toDateString();
				return (startDtStr ===  evtDtStr || 
						endDtStr === evtDtStr || 
						(startDt < evtDt && evtDt < endDt));
			}
		};
		var onEventRender = function (event, element) {
			var color = '#3366CC';
			switch (event.title) {
				case 'closed': color = '#000000'; break;
				case 'proof': color = that.color.proof; break;
				case 'print': color = that.color.print; break;
				case 'ship': color = that.color.ship; break;
				case 'arrive on': color = that.color.arrive; break;
				case 'deadline': color = that.color.deadline; break;
			}
			element.css('background-color', color)
				   .css('border-color', color)
			       .children('a')
				       .css('border-color', color)
				       .css('background-color', color);
			if ((event.start.getDay() === 0 || event.start.getDay() === 6) && event.title === "closed") {
				return false;
			}
		};
		var findDayOnCoord = function(xcoord, ycoord) {
			var elToReturn = null;
			$("div.fc-view tr").each(function() {
			    var trow = $(this);
			    var trowMin = trow.offset().top;
			    var trowMax = trowMin + trow.height();
			    if (trowMin < ycoord && trowMax > ycoord) {
			        trow.children("td").each(function() {
			            var tcol = $(this);
			            var tcolMin = tcol.offset().left;
			            var tcolMax = tcolMin + tcol.width();
			            if (tcolMin < xcoord && tcolMax > xcoord) {
			            	elToReturn = tcol;
						}
			        });
			    } 
			});
			return elToReturn;
		};
		var onEventClick = function(calEvent, jsEvent, view) {
			//delegate to dayClick
			var eX = jsEvent.pageX, eY = jsEvent.pageY;
			var objToTraverse = $("div#fc-view tr");
			var underlyingDay = findDayOnCoord(eX, eY);
			if (underlyingDay) {
				underlyingDay.trigger('click');
			}
		};
		// the events represent the life cycle of a job
		var jobLife = [];
		var onDayClick = function(date, allDay, jsEvent, view) {
			if (that.dayClickSyncOn) {
				return; // lock already acquired, go on our merry way
			}
			that.dayClickSyncOn = true;
			that.lastDayPicked = date;
			that.ui.clear.messages();
			var postcallback = function () {
				if (jobLife.length > 0) {
					// remove old life cycle
					transitCal.fullCalendar('removeEventSource', jobLife);
				}
				// clear the array
		        while (jobLife.length > 0) jobLife.pop();
		        // now see whether we've landed on a 'legal' date
		        var daysOff = transitCal.fullCalendar('clientEvents', genDateFilter(today, date));
		        var dateStr = date.toDateString();
		        var cannotArrive = false;
		        var isClosed = false;
		        if (daysOff.length > 0) {				        
			        var lastDay = daysOff[daysOff.length - 1].start;
			        if (lastDay.toDateString() === dateStr) {
			        	isClosed = true;
			        }
		        }
		        
		        var days = Math.floor((date - today) / that.one_day);
		        if (cutoff < today && date > today) days -= 1; // after hours
		        
		        var basicMsg;
		        if (days <= 0) {
		        	basicMsg = "you've picked: " + that.formatDate(date) +" which is on or before today";
		        	that.ui.write.basic(basicMsg);
		        	// need to release lock here
		        	that.dayClickSyncOn = false;		        	
		        } else if (cannotArrive) {
		        	basicMsg = "order cannot arrive on: " + that.formatDate(date);
		        	that.ui.write.basic(basicMsg);
		        	// need to release lock here
		        	that.dayClickSyncOn = false;
		        } else if (isClosed) {
		        	basicMsg = "Unfortunately, we cannot ship orders to arrive on a weekend or holidays. Please choose another date.";
		        	that.ui.write.basic(basicMsg);
		        	// need to release lock here
		        	that.dayClickSyncOn = false;
		        } else {
		        	var numDaysOff = daysOff.length;
		        	basicMsg = "To have your order delivered on or by <span style=\"font-weight: bold;\">" + that.formatDate(date) + "</span>";
		        	that.ui.write.basic(basicMsg);
		        	
					var calculateArrival = function(extraShip) {
						var allowableShipping = [];
						// we construct the allowable shipping options based on what we know
						if (that.shipMethod === "ship") {
							var maxShipDays = 3;
							var groundMethod;
							if (extraShip && extraShip["ground"] >= 0) {
								// ground shipping available
								groundMethod = { method: "UPS Ground", days: extraShip["ground"] };
							}
							if (extraShip && extraShip["local"] >= 0) {
								// only add if ground is less viable
								if (groundMethod && groundMethod["days"] > 1)
									allowableShipping.push({ method: "local delivery", days: 1 });
								maxShipDays = 0; // no need to consider regular shipping, then
							}
							for (var i = allowableShipping.length + 1; i <= maxShipDays; i++) {
								if (groundMethod && groundMethod["day"] <= i) break; // no need to offer when ground suffice
								var methodName;
								if (i == 1) {
									methodName = "UPS Next Day Air";
								} else if (i == 2) {
									methodName = "UPS Second Day Air";									
								} else if (i == 3) {
									methodName = "UPS Three Day Select";									
								} else {
									methodName = i + " day ship";
								}
								allowableShipping.unshift({method: methodName, days: i});
							}
							if (groundMethod) {
								allowableShipping.unshift(groundMethod);
							}
						} else {
							allowableShipping.push({method: "pickup", days: 0});
						}
						// take into account the days available
						var chosenTurnaround, chosenShip;
						var usableDays = days - numDaysOff;
						var rushFlag = false;
						for (var i = 0; i < that.turnarounds.length; i++) {
							var isRush = function(turn) { 
								return turn === that.turnarounds[0];
							}; // turnaround is rush
							var turnDays = that.turnarounds[i];
							if (turnDays <= usableDays) {
								var canShipDays = usableDays - turnDays;
								for (var j = 0; j < allowableShipping.length; j++) {
									var allowableShip = allowableShipping[j];
									var shipDays = allowableShip["days"];
									if (shipDays <= canShipDays) {
										// we can use this option to ship
										// if this is the first usable choice we come across, we'll use it regardless
										if (typeof chosenShip == "undefined") {
											chosenShip = allowableShip;
										}
										if (typeof chosenTurnaround == "undefined") {
											chosenTurnaround = turnDays;
										}
										if (!rushFlag && !isRush(turnDays) && isRush(chosenTurnaround) && chosenShip["days"] > chosenTurnaround) {
											// special condition for rush: if the current turnaround is ship and less than ship, look for less rushed
											chosenShip = allowableShip;
											chosenTurnaround = turnDays;
											rushFlag = true;
										} else if (shipDays >= chosenShip["days"]) {
											// only advance turnaround the choice if shipping doesn't decrement
											chosenShip = allowableShip;
											chosenTurnaround = turnDays;			
										}
									}																					
								}
							}
						}
					
						// format the info
						if (typeof chosenShip != "undefined" && typeof chosenTurnaround != "undefined") {
							// plot out the timeline
							var dayWalker = new Date();
							dayWalker.setHours(0);
							dayWalker.setMinutes(0);
							dayWalker.setSeconds(0);
							dayWalker.setMilliseconds(0);
							var daysWalked = [];
							var curDaysOffPtr = 0;
							do {
								while (curDaysOffPtr < daysOff.length && daysOff[curDaysOffPtr].start < dayWalker) {
									curDaysOffPtr += 1;
								}
								if (daysOff[curDaysOffPtr] && daysOff[curDaysOffPtr].start.toDateString() === dayWalker.toDateString()) {
									// day off, don't use it
								} else {
									daysWalked.push(dayWalker);
								}
								dayWalker = new Date(dayWalker.getTime() + that.one_day);										
							} while (dayWalker <= date);
							if (daysWalked.length > 0) {
								
								var proofEvtStart = 0;
								var proofEvtEnd = proofEvtStart + (cutoff < today ? 2 : 1);
								var printEvtStart = proofEvtEnd + 1;
								var printEvtEnd = printEvtStart + chosenTurnaround - 1;
								var shipEvtStart = printEvtEnd; 
								var shipEvtEnd = printEvtEnd + chosenShip["days"];
					        	jobLife.push({title: "proof", start: daysWalked[proofEvtStart], end: daysWalked[proofEvtEnd]});
					        	jobLife.push({title: "print", start: daysWalked[printEvtStart], end: daysWalked[printEvtEnd]});
					        	if (chosenShip["days"] > 0)
					        		jobLife.push({title: "ship", start: daysWalked[shipEvtStart], end: daysWalked[shipEvtEnd]});
					        	jobLife.push({title: "arrive on", start: daysWalked[shipEvtEnd]});
					        	if (daysWalked[shipEvtEnd] < daysWalked[daysWalked.length - 1]) {
					        		jobLife.push({title: "deadline", start: daysWalked[daysWalked.length - 1]});
					        	}
								transitCal.fullCalendar('addEventSource', jobLife);
								that.ui.append.basic(" you will need to choose: ");
								var detailMsg = ' \
									<ul style="margin-left: 5px; padding-left: 5px;"> \
										<li>Our <span style="font-weight: bold;">' + that.turnNames[chosenTurnaround] + 'Turnaround</span>.</li> \
										<li>Ship via <span style="font-weight: bold;">' + chosenShip["method"] + '</span>.</li> \
										<li>And approve your proof by <span style="font-weight: bold;">5 PM Pacific Time on ' + that.formatDate(daysWalked[proofEvtEnd]) + '</span>.</li> \
									</ul>';
								that.ui.write.detail(detailMsg);
								var afterMsg = "";
								afterMsg += "Turnaround times are estimated with PDF proofs. Hard proofs will add additional time. ";
								afterMsg += "Our suggestions are not always the only option to meet your deadline.";
								that.ui.write.after(afterMsg);
								that.ui.toggleTurnaround(chosenTurnaround, chosenShip, date, $(":input[name='zipIntent']").val());
							}
						} else {
							that.ui.append.basic(" you should: ");
							that.ui.write.detail("<ul style=\"margin-left: 5px; padding-left: 5px;\"><li>" +
									"Contact a Customer Service Representative as we cannot fulfill your order " +
									"within that period using standard turnaround and shipping.</li></ul>");
						}
						that.ui.clear.title();
						that.ajaxLoader.off();
				        // release the lock
						that.dayClickSyncOn = false;
					};
					// figure in shipping
					if (that.shipMethod) {
						if (that.shipMethod === "ship") {
							var zip = $(":input[name='zipIntent']").val();
							if (zip) {
								that.ui.write.loader("calculating turnaround and shipping...");
								that.ajaxLoader.on();
								that.getGroundTime(zip, calculateArrival);
							} else {
								calculateArrival();
							}
						} else {
							calculateArrival();
						}
					} else {
						// need to make sure all pathways release lock
						that.dayClickSyncOn = false;						
					}
		        }
		    };
		    if (that.calSvc.events.get(date.getMonth(), date.getFullYear())) {
		    	// we have full set of events to proceed
		    	postcallback();
		    } else {
		    	// need to retrieve the event, then call
		    	that.popEvents(date.getMonth(), date.getFullYear(), postcallback);
		    }		    	
	    };
	    
		transitCal.fullCalendar({
			editable: false,
			weekends: true,
			eventRender: onEventRender,
			dayClick: onDayClick,
			eventClick: onEventClick
		});
		// we'll attach the day click function to our object so we can reuse it
		that.triggerOnDayClick = onDayClick;
	}
	this.initMonth();
	this.ajaxLoader.init();
};
planningCalculator.shipMethod = null;
// used to bind events for going between shipping methods
planningCalculator.initShipMethodEvents = function () {
	var that = this;
	var triggerDayClick = function () {
		if (that.lastDayPicked) {
			that.triggerOnDayClick(that.lastDayPicked);
		}
	};
	var shipIntentRadio = $(":radio[name='shipIntent']");
	shipIntentRadio.click(function (e) {
		that.shipMethod = this.value;
		triggerDayClick();
	});
	$("#zipIntentButton").click(function (e) { triggerDayClick(); });
	// set default value to ship instead of pickup
	$(":radio[value='ship']").click();
	// if we press enter we trigger
	$(":input[name='zipIntent']").bind('keypress', function(e) {
		if (e.which == 13) {
			triggerDayClick();			
		}
	});
};
// used to bind events for transitioning between months
planningCalculator.initMonth = function () {
	// bind some custom callbacks
	var that = this;
	var grabMonth = function () {
		var calDate = that.transitCal.fullCalendar('getDate');
		that.popEvents(calDate.getMonth(), calDate.getFullYear());
	};
	
	$(".fc-button-prev").bind('click', grabMonth);
	$(".fc-button-next").bind('click', grabMonth);
	$(".fc-button-today").bind('click', grabMonth);
};
//used to position ajax loader
planningCalculator.ajaxLoader = function () {
	var ldr;
	return {
    	init: function () {
			ldr = $("#ajaxLoader");
		},
    	on: function () {
			var transitCal = $("#transitCal");
			ldr.width(transitCal.width()).height(transitCal.height());
			ldr.show();
		},
    	off: function () {
			ldr.hide();
		}
	};
}();
// used to self-start the calculator
planningCalculator.selfStart = function (onNever) {
	var starter = $('\
	<div> \
	  Do you have a deadline for your project but find the planning daunting? \
	  You can use our project planner to set your deadline and we can handle your \
	  turnaround and shipping for you! <br/><br/>\
	  <a id="planHandlerInitNo" href="javascript:void(0);" class="orangeButton"><span>No Thanks</span></a> \
	  <a id="planHandlerInitYes" href="javascript:void(0);" class="orangeButton"><span>Yes Please</span></a> \
	  <a id="planHandlerInitNever" href="javascript:void(0);" class="orangeButton"><span>Don\'t Bother Me</span></a> \
	</div> \
	');
	var closer = function() {
	  $(document).trigger('close.facebox');
	  starter.remove();
	};
	starter.find('#planHandlerInitNo').bind('click', closer);
	starter.find('#planHandlerInitYes').bind('click', function() {
		$(document).bind('afterClose.facebox', function() {
			$(document).unbind('afterClose.facebox');
			calcTransitTime();			
		});
		closer();
	});
	starter.find('#planHandlerInitNever').bind('click', function() {
		closer();
		onNever();
	});
	$.facebox({ 'inject': starter });
};
planningCalculator.transitBoxCache = null;
function calcTransitTime() {
	var presetWidth;
	if (!planningCalculator.transitBoxCache) {
		// no injection yet, do init
		planningCalculator.transitBoxCache = $('#transitContent');
		presetWidth = planningCalculator.transitBoxCache.css('width');
		planningCalculator.transitBoxCache.detach();
		$(document).bind('beforeReveal.facebox', function() {
			planningCalculator.transitBoxCache.show();
		});
		$(document).bind('reveal.facebox', function() {
			$(".fc-button-today").click();
		});
		$(document).bind('close.facebox', function() {
			planningCalculator.dayClickSyncOn = false;
			planningCalculator.transitBoxCache.detach();
		});
	}
	$.facebox({ 'inject': planningCalculator.transitBoxCache });
	if (presetWidth) {
		// manual override just in case browser like ie doesn't
		$("#facebox .content").css('width', presetWidth);
	}
}
