/***************************************************************
Copyright 2008 Mandogroup Ltd
Modules: CSS Dropdowns,Flash Detection,Date Picker,ToolTips,Tree,Date,Element,Inline Popup,Morph,Overlay,URLParser,
Notes: 
***************************************************************/

/**************************************************************

	Script		: CSS Dropdowns
	Version		: 1.0
	Authors		: Samuel Birch
	Desc		: Dropdown menus

**************************************************************/

var dropdownMenu = new Class({
	
	initialize: function(myMenu,options){
		options = Object.extend({

		}, options || {});
		
		this.myMenu = $(myMenu);
		this.myElements = $$('#'+this.myMenu.id+' li');
		
		this.myElements.each(function(el, i){
			el.addEvent('mouseover', function(e){
				el.addClass('sfhover');
			});
			
			el.addEvent('mouseout', function(e){
				el.removeClass('sfhover');
			});
		});
	}
	
});


/*************************************************************/

/**************************************************************

	Script		: Flash Detection (SWF Object)
	Version		: 1.4
	Authors		: Deconcept
	Desc		: flash player detection and embeding.

**************************************************************/

if(typeof deconcept == "undefined") var deconcept = new Object();
if(typeof deconcept.util == "undefined") deconcept.util = new Object();
if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object();
deconcept.SWFObject = function(swf, id, w, h, ver, c, useExpressInstall, quality, xiRedirectUrl, redirectUrl, detectKey){
	if (!document.getElementById) { return; }
	this.DETECT_KEY = detectKey ? detectKey : 'detectflash';
	this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY);
	this.params = new Object();
	this.variables = new Object();
	this.attributes = new Array();
	if(swf) { this.setAttribute('swf', swf); }
	if(id) { this.setAttribute('id', id); }
	if(w) { this.setAttribute('width', w); }
	if(h) { this.setAttribute('height', h); }
	if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); }
	this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion();
	if(c) { this.addParam('bgcolor', c); }
	var q = quality ? quality : 'high';
	this.addParam('quality', q);
	this.setAttribute('useExpressInstall', useExpressInstall);
	this.setAttribute('doExpressInstall', false);
	var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location;
	this.setAttribute('xiRedirectUrl', xir);
	this.setAttribute('redirectUrl', '');
	if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); }
}
deconcept.SWFObject.prototype = {
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name];
	},
	addParam: function(name, value){
		this.params[name] = value;
	},
	getParams: function(){
		return this.params;
	},
	addVariable: function(name, value){
		this.variables[name] = value;
	},
	getVariable: function(name){
		return this.variables[name];
	},
	getVariables: function(){
		return this.variables;
	},
	getVariablePairs: function(){
		var variablePairs = new Array();
		var key;
		var variables = this.getVariables();
		for(key in variables){
			variablePairs.push(key +"="+ variables[key]);
		}
		return variablePairs;
	},
	getSWFHTML: function() {
		var swfNode = "";
		if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
			if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "PlugIn"); }
			swfNode = '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'"';
			swfNode += ' id="'+ this.getAttribute('id') +'" name="'+ this.getAttribute('id') +'" ';
			var params = this.getParams();
			 for(var key in params){ swfNode += [key] +'="'+ params[key] +'" '; }
			var pairs = this.getVariablePairs().join("&");
			 if (pairs.length > 0){ swfNode += 'flashvars="'+ pairs +'"'; }
			swfNode += '/>';
		} else { // PC IE
			if (this.getAttribute("doExpressInstall")) { this.addVariable("MMplayerType", "ActiveX"); }
			swfNode = '<object id="'+ this.getAttribute('id') +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'">';
			swfNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />';
			var params = this.getParams();
			for(var key in params) {
			 swfNode += '<param name="'+ key +'" value="'+ params[key] +'" />';
			}
			var pairs = this.getVariablePairs().join("&");
			if(pairs.length > 0) {swfNode += '<param name="flashvars" value="'+ pairs +'" />';}
			swfNode += "</object>";
		}
		return swfNode;
	},
	write: function(elementId){
		if(this.getAttribute('useExpressInstall')) {
			// check to see if we need to do an express install
			var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]);
			if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
				this.setAttribute('doExpressInstall', true);
				this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				this.addVariable("MMdoctitle", document.title);
			}
		}
		if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
			var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
			n.innerHTML = this.getSWFHTML();
			return true;
		}else{
			if(this.getAttribute('redirectUrl') != "") {
				document.location.replace(this.getAttribute('redirectUrl'));
			}
		}
		return false;
	}
}

/* ---- detection functions ---- */
deconcept.SWFObjectUtil.getPlayerVersion = function(){
	var PlayerVersion = new deconcept.PlayerVersion([0,0,0]);
	if(navigator.plugins && navigator.mimeTypes.length){
		var x = navigator.plugins["Shockwave Flash"];
		if(x && x.description) {
			PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
		}
	}else{
		// do minor version lookup in IE, but avoid fp6 crashing issues
		// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
		try{
			var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		}catch(e){
			try {
				var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				PlayerVersion = new deconcept.PlayerVersion([6,0,21]);
				axo.AllowScriptAccess = "always"; // throws if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
			} catch(e) {
				if (PlayerVersion.major == 6) {
					return PlayerVersion;
				}
			}
			try {
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			} catch(e) {}
		}
		if (axo != null) {
			PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
		}
	}
	return PlayerVersion;
}
deconcept.PlayerVersion = function(arrVersion){
	this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0;
	this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0;
	this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0;
}
deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
	if(this.major < fv.major) return false;
	if(this.major > fv.major) return true;
	if(this.minor < fv.minor) return false;
	if(this.minor > fv.minor) return true;
	if(this.rev < fv.rev) return false;
	return true;
}
/* ---- get value of query string param ---- */
deconcept.util = {
	getRequestParameter: function(param) {
		var q = document.location.search || document.location.hash;
		if(q) {
			var pairs = q.substring(1).split("&");
			for (var i=0; i < pairs.length; i++) {
				if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
					return pairs[i].substring((pairs[i].indexOf("=")+1));
				}
			}
		}
		return "";
	}
}
/* fix for video streaming bug */
deconcept.SWFObjectUtil.cleanupSWFs = function() {
	if (window.opera || !document.all) return;
	var objects = document.getElementsByTagName("OBJECT");
	for (var i=0; i < objects.length; i++) {
		objects[i].style.display = 'none';
		for (var x in objects[i]) {
			if (typeof objects[i][x] == 'function') {
				objects[i][x] = function(){};
			}
		}
	}
}
// fixes bug in fp9 see http://blog.deconcept.com/2006/07/28/swfobject-143-released/
deconcept.SWFObjectUtil.prepUnload = function() {
	__flash_unloadHandler = function(){};
	__flash_savedUnloadHandler = function(){};
	if (typeof window.onunload == 'function') {
		var oldUnload = window.onunload;
		window.onunload = function() {
			deconcept.SWFObjectUtil.cleanupSWFs();
			oldUnload();
		}
	} else {
		window.onunload = deconcept.SWFObjectUtil.cleanupSWFs;
	}
}
if (typeof window.onbeforeunload == 'function') {
	var oldBeforeUnload = window.onbeforeunload;
	window.onbeforeunload = function() {
		deconcept.SWFObjectUtil.prepUnload();
		oldBeforeUnload();
	}
} else {
	window.onbeforeunload = deconcept.SWFObjectUtil.prepUnload;
}
/* add Array.push if needed (ie5) */
if (Array.prototype.push == null) { Array.prototype.push = function(item) { this[this.length] = item; return this.length; }}

/* add some aliases for ease of use/backwards compatibility */
var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for legacy support
var SWFObject = deconcept.SWFObject;

/*************************************************************/
/**************************************************************

	Script		: Date Picker
	Version	: 1.2
	Authors	: Samuel Birch
	Desc		: Popup calendar for form fields

**************************************************************/

var DatePicker = new Class({
	
	fullDay: 86400000,
	
	getOptions: function(){
		return {
			calendarId: false,
			months: ["January","February","March","April","May","June","July","August","September","October","November","December"],
			days: ["Su","Mo","Tu","We","Th","Fr","Sa"],
			popupOptions: {
				position: "bottomLeft",
				offset: {x:10, y:10},
				fadeDuration: 400
			},
			iconImage: 'calendar.gif',
			iconClassName: 'DatePickerIcon',
			showOnInputFocus: true,
			disableInput: false,
			hideCalendarOnPick: true,
			dayInput: false,
			monthInput: false,
			yearInput: false,
			yearRange: {},
			onPick: Class.empty,
			onShow: Class.empty,
			onHide: Class.empty
		};
	},

	initialize: function(input, options){
		this.setOptions(this.getOptions(), options);
		
		if(!this.options.calendarId) this.options.calendarId = "popupCalendar" + new Date().getTime();
		
		//add picker icon
		//this.icon = new Element('div').setProperties({id: this.options.calendarId+'_icon'}).addClass(this.options.iconOptions.className).setStyles({width: this.options.iconOptions.width, height: this.options.iconOptions.height});
		this.icon = new Element('img').setProperties({id: this.options.calendarId+'_icon', src: this.options.iconImage}).addClass(this.options.iconClassName);
		this.icon.addEvent('click', this.show.bind(this));
		
		
		if(input != ''){
			this.input = $(input);
			this.setUpObservers();
			this.icon.injectAfter(this.input);
		}else{
			this.input = false;
			this.options.dayInput = $(this.options.dayInput);
			this.options.monthInput = $(this.options.monthInput);
			this.options.yearInput = $(this.options.yearInput);
			this.populateInputs();
			this.icon.injectAfter(this.options.yearInput);
		}
		
		
		if(this.options.disableInput){
			this.input.defaultValue = this.input.value;
			this.input.addEvents({
				'keydown': function(){
					this.value = this.defaultValue;
				},
				'keyup': function(){
					this.value = this.defaultValue;
				}
			});
		}
		this.getCalendar();
		
	},
	
	setUpObservers: function(){
		if (this.options.showOnInputFocus) this.input.addEvent('focus', this.show.bind(this));
		try {this.input.addEvent('blur', this.updateInput.bind(this));}catch(e){} //ie sometimes doesn't like this.
	},
	
	populateInputs: function(){
		new Element('option').injectInside(this.options.dayInput);
		for(i=1;i<32;i++){
			new Element('option').setProperty('value',i).setHTML(i).injectInside(this.options.dayInput);
		}
		
		new Element('option').injectInside(this.options.monthInput);
		for(i=1;i<13;i++){
			new Element('option').setProperty('value',i).setHTML(i).injectInside(this.options.monthInput);
		}
		
		new Element('option').injectInside(this.options.yearInput);
		for(i=this.options.yearRange.start;i<this.options.yearRange.end+1;i++){
			new Element('option').setProperty('value',i).setHTML(i).injectInside(this.options.yearInput);
		}
	},
	
	/*	Property: updateInput
		Takes a given date and updates the input field with its value.
		
		Arguments:
		date - a date or a string that is parsable as a date (see <validDate>)
	*/
	updateInput: function(date){
		//if(!$type(date) == "string" || (date && !date.getTime)) date = this.input.getValue();
		if(this.input == false){
			date = this.options.dayInput.getValue()+'/'+this.options.monthInput.getValue()+'/'+this.options.yearInput.getValue();
		}else{
			date = this.input.getValue();
		}
		if(date != ''){
			if(!Date.isValid(date)){
				var dateStr = new Date().format('dd/MM/yyyy');
			}else{
				var dateStr = Date.parseString(date).format('dd/MM/yyyy');
			}
			
			if($type(dateStr) == "string") {
				this.input.value = dateStr;
				return dateStr;
			}
			return date;
		}
	},

	validDate: function(val) {
		return Date.parseString(val);
	},

	formatDate: function (date) {
		return date.format('dd/MM/yyyy');
	},
	
	zeroHourGMT: function(date) {
		//date.setTime(date.getTime() - date.getTime() % 86400000);
		date = new Date(date.getFullYear()+'/'+(date.getMonth()+1)+'/'+date.getDate());
		return date;
	},
		
	getCalendar: function() {
		if(!this.calendar) {
			var cal = new Element("table").setProperties({
				'id': this.options.calendarId,
				'border':'0',
				'cellpadding':'0',
				'cellspacing':'0'
			});
			cal.addClass('datePicker');
		$(cal.insertRow(0).insertCell(0)).appendText("#");
			for (var c=0;c<6;c++) $(cal.rows[0]).adopt(cal.rows[0].cells[0].cloneNode(true));
			for (var r=0;r<7;r++) $(cal.rows[0].parentNode).adopt(cal.rows[0].cloneNode(true));
			$(cal.rows[1]).addClass('dayNames');
			for (var r=2;r<8;r++) $(cal.rows[r]).addClass('dayRow');
			for (var d=0;d<7;d++) cal.rows[1].cells[d].firstChild.data = this.options.days[d];
			for (var t=6;t>3;t--) cal.rows[0].deleteCell(t);
			$(cal.rows[0]).addClass('dateNav');
			
			this.preArrow = new Element('div').setProperty('id','dpPreviousYear').injectInside(cal.rows[0].cells[0]);
			cal.rows[0].cells[0].firstChild.data='<';
			cal.rows[0].cells[1].colSpan=4;
			this.nextArrow = new Element('div').setProperty('id','dpNextYear').injectInside(cal.rows[0].cells[2]);
			cal.rows[0].cells[2].firstChild.data='>';
			
			$(cal.rows[0].cells[3].setHTML('')).adopt(this.getCloseImg());
			
			cal.addEvent('click', this.clickCalendar.bind(this));
			this.calendar = cal;
			this.container = new Element('div').adopt(cal).addClass('calendarHolder');
			//make stickywin
			this.options.popupOptions.content = this.container;
			//this.options.popupOptions.showNow = false;
			if(this.input == false){
				this.options.popupOptions.relativeTo = this.options.dayInput;
			}else{
				this.options.popupOptions.relativeTo = this.input;
			}
			this.options.popupOptions.height = this.container.getStyle('height').toInt();
			this.options.popupOptions.width = this.container.getStyle('width').toInt();
			
			this.popup = new InlinePopup(this.options.popupOptions);
		}
		return this.calendar;
	},
/*	Properties: getCloseImg
		Returns an img object to use for the close funciton.
		
		You can use <Class.implement> to redefine this so that it returns a dom element of your choosing.
		You will need to add your own call to <DatePicker.hide>.
	*/
	getCloseImg: function(){
		var closer = new Element('div').setProperty('id', 'datePickerClosebtn').addClass('closebtn');
		closer.addEvents({
			'mouseover': function(){
				closer.addClass('closebtnOver');
			},
			'mouseout': function(){
				closer.removeClass('closebtnOver');
			},
			'click': this.hide.bind(this)
		});
		return closer;
	},
		
/*	Property: hide
		Hides the calendar popup.
	*/
	hide: function(){
		this.popup.hide();
		this.fireEvent('onHide');
	},
/*	Property: show
		Shows the calendar popup. This will reposition the popup and display the date that the user has entered or today's date if they have not entered anything.
	*/
	show: function(){
		this.today = this.zeroHourGMT(new Date());
		//console.log(this.today)
		this.inputDate = Date.parseString(this.updateInput());
		if(this.inputDate == null){
			this.refDate = this.today;
		}else{
			this.refDate = this.inputDate;
		}
	//this.refDate = isNaN(this.inputDate) ? this.zeroHourGMT(new Date(this.inputDate)) : this.today;
		this.getCalendar();
		this.fillCalendar(this.refDate);
		this.popup.show();
		this.fireEvent('onShow');
	},
	
	clickCalendar: function(e) {
		e = new Event(e);
		if (!e.target.firstChild || !e.target.firstChild.data) return null;
		var val = e.target.firstChild.data;
		if (val == "<" || val == ">") {
			var newRef = this.calendar.rows[2].cells[0].refDate - this.fullDay;
			if (val != "<"){
				var next = true;
				newRef = this.calendar.rows[7].cells[6].refDate + this.fullDay;
			}
			if(this.options.yearRange.start){
				if(next){
					if(new Date(newRef) < new Date((this.options.yearRange.end+1)+'/01/01')){
						this.fillCalendar(new Date(newRef));
						this.preArrow.show();
						if(new Date(this.calendar.rows[7].cells[6].refDate + this.fullDay) >= new Date((this.options.yearRange.end+1)+'/01/01')){
							this.nextArrow.hide();
						}else{
							this.nextArrow.show();
						}
					}
				}else{
					if(new Date(newRef) > new Date(this.options.yearRange.start+'/01/01')){
						this.fillCalendar(new Date(newRef));
						this.nextArrow.show();
						if(new Date(this.calendar.rows[2].cells[0].refDate - this.fullDay) <= new Date((this.options.yearRange.start)+'/01/01')){
							this.preArrow.hide();
						}else{
							this.preArrow.show();
						}
					}
				}
			}else{
				this.fillCalendar(new Date(newRef));
			}
			return null;
		}
		if (e.target.refDate) {
			var newDate = new Date(e.target.refDate);
			if(this.input != false){
				this.input.value = this.formatDate(newDate);
				this.input.defaultValue = this.input.value;
				/* trip onchange events in text field */
				this.input.fireEvent("change");
				this.input.fireEvent("blur");
				this.fireEvent('onPick');
			}else{
				this.options.dayInput.value = newDate.getDate();
				this.options.monthInput.value = newDate.getMonth()+1;
				this.options.yearInput.value = newDate.getFullYear();
			}
			if(this.options.hideCalendarOnPick) this.hide();
		}
	},
	
	fillCalendar: function (forDate) {
		//console.log(forDate)
		var startDate = new Date(forDate);
		startDate.setDate(1);
		//console.log(startDate)
		startDate.setTime(startDate.getTime() - (this.fullDay * startDate.getDay()));
		//console.log(startDate)
		this.calendar.rows[0].cells[1].firstChild.data = this.options.months[forDate.getUTCMonth()] + " " + forDate.getUTCFullYear();
		var atDate = startDate;
		this.calendar.getElements('td').each(function (el){
			el.removeClass('selectedDate').removeClass('otherMonthDate').removeClass('today');
		});
		
		for (var w=2; w<8; w++) for (var d=0; d<7; d++) {
			var td = this.calendar.rows[w].cells[d];
			td.firstChild.data = atDate.getDate();
			//console.log(td.firstChild.data);
			td.refDate = atDate.getTime();
			//console.log(atDate +' : '+this.today)
			if(atDate.getTime() == this.today.getTime()) td.addClass('today');
			if(atDate.getTime() == this.refDate.getTime()) td.addClass('selectedDate');
			//console.log(atDate.getMonth() +' : '+forDate.getMonth())
			if(atDate.getMonth() != forDate.getMonth()) td.addClass('otherMonthDate');
			atDate.setTime(atDate.getTime() + this.fullDay);
		}
	}

});

DatePicker.implement(new Options);
DatePicker.implement(new Events);


/*************************************************************/
/**************************************************************

	Script		: Tool Tips
	Version		: 1.0
	Authors		: Valerio Proietti
	Desc		: Tooltips

**************************************************************/

var Tips = new Class({

	options: {
		onShow: function(tip){
			tip.setStyle('visibility', 'visible');
		},
		onHide: function(tip){
			tip.setStyle('visibility', 'hidden');
		},
		maxTitleChars: 30,
		showDelay: 100,
		hideDelay: 100,
		className: 'tool',
		offsets: {'x': 16, 'y': 16},
		fixed: false
	},

	initialize: function(elements, options){
		this.setOptions(options);
		this.toolTip = new Element('div', {
			'class': this.options.className + '-tip',
			'styles': {
				'position': 'absolute',
				'top': '0',
				'left': '0',
				'visibility': 'hidden'
			}
		}).inject(document.body);
		this.wrapper = new Element('div').inject(this.toolTip);
		$$(elements).each(this.build, this);
		if (this.options.initialize) this.options.initialize.call(this);
	},

	build: function(el){
		el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
		if (el.title){
			var dual = el.title.split('::');
			if (dual.length > 1){
				el.$tmp.myTitle = dual[0].trim();
				el.$tmp.myText = dual[1].trim();
			} else {
				el.$tmp.myText = el.title;
			}
			el.removeAttribute('title');
		} else {
			el.$tmp.myText = false;
		}
		if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
		el.addEvent('mouseenter', function(event){
			this.start(el);
			if (!this.options.fixed) this.locate(event);
			else this.position(el);
		}.bind(this));
		if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
		var end = this.end.bind(this);
		el.addEvent('mouseleave', end);
		el.addEvent('trash', end);
	},

	start: function(el){
		this.wrapper.empty();
		if (el.$tmp.myTitle){
			this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)).setHTML(el.$tmp.myTitle);
		}
		if (el.$tmp.myText){
			this.text = new Element('span').inject(new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)).setHTML(el.$tmp.myText);
		}
		$clear(this.timer);
		this.timer = this.show.delay(this.options.showDelay, this);
	},

	end: function(event){
		$clear(this.timer);
		this.timer = this.hide.delay(this.options.hideDelay, this);
	},

	position: function(element){
		var pos = element.getPosition();
		this.toolTip.setStyles({
			'left': pos.x + this.options.offsets.x,
			'top': pos.y + this.options.offsets.y
		});
	},

	locate: function(event){
		var win = {'x': window.getWidth(), 'y': window.getHeight()};
		var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
		var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
		var prop = {'x': 'left', 'y': 'top'};
		for (var z in prop){
			var pos = event.page[z] + this.options.offsets[z];
			if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
			this.toolTip.setStyle(prop[z], pos);
		};
	},

	show: function(){
		if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
		this.fireEvent('onShow', [this.toolTip]);
	},

	hide: function(){
		this.fireEvent('onHide', [this.toolTip]);
	}

});

Tips.implement(new Events, new Options);

/*************************************************************/


/**************************************************************

	Script		: Tree
	Version		: 1.0
	Authors		: Samuel Birch
	Desc		: Opening & closing of nested list items.

**************************************************************/

var Tree = new Class({
							  
	getOptions: function(){
		return {
			clsHide: 'hideMe',
			clsParent: 'parent',
			clsOpened: 'opened',
			clsClosed: 'closed',
			trigger: 'span',
			autoOpen: false,
			queryName: 'openTree'
		};
	},

	initialize: function(tree, options){
		this.setOptions(this.getOptions(), options);
		
		this.tree = $(tree);
		this.elements = this.tree.getElements('.'+this.options.clsParent);
		
		this.elements.each(function(el,i){
			el.addClass(this.options.clsClosed);
			el.getElement(this.options.trigger).addEvent('click',this.openClose.bind(this, el));
		}, this);
		
		//auto open
		if(this.options.autoOpen){
			this.queryItems = parseUrl(window.location.href)['query'].split('&');
			this.queryItems.each(function(el,i){
				var temp = el.split('=');
				if(temp[0] == this.options.queryName){
					var t = temp[1].split(',');
					t.each(function(el){
						this.open(el);
					}, this);
				}
			}, this);
		}
	},
	
	openClose: function(el){
		var ul = el.getElement('ul');
		if(ul.hasClass(this.options.clsHide)){
			ul.removeClass(this.options.clsHide);
			el.removeClass(this.options.clsClosed);
			el.addClass(this.options.clsOpened);
		}else{
			ul.addClass(this.options.clsHide);
			el.removeClass(this.options.clsOpened);
			el.addClass(this.options.clsClosed);
		}
	},
	
	open: function(id){
		var el = $(id);
		if(el != this.tree){
			if(el.hasClass(this.options.clsParent)){
				this.openClose(el);
			}
			this.open(el.getParent());
		}
	}

});
Tree.implement(new Events);
Tree.implement(new Options);

/*************************************************************/


/**************************************************************

	Script		: Date
	Version		: 1.02
	Authors		: Matt Kruse
	Desc		: Extends the <Date> prototype.

**************************************************************/


Date.$VERSION = 1.02;

// Utility function to append a 0 to single-digit numbers
Date.LZ = function(x) {return(x<0||x>9?"":"0")+x};
// Full month names. Change this for local month names
Date.monthNames = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
// Month abbreviations. Change this for local month names
Date.monthAbbreviations = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
// Full day names. Change this for local month names
Date.dayNames = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
// Day abbreviations. Change this for local month names
Date.dayAbbreviations = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
// Used for parsing ambiguous dates like 1/2/2000 - default to preferring 'American' format meaning Jan 2.
// Set to false to prefer 'European' format meaning Feb 1
Date.preferAmericanFormat = false;

// If the getFullYear() method is not defined, create it
if (!Date.prototype.getFullYear) { 
	Date.prototype.getFullYear = function() { var yy=this.getYear(); return (yy<1900?yy+1900:yy); } 
} 

// Parse a string and convert it to a Date object.
// If no format is passed, try a list of common formats.
// If string cannot be parsed, return null.
// Avoids regular expressions to be more portable.
Date.parseString = function(val, format) {
	// If no format is specified, try a few common formats
	if (typeof(format)=="undefined" || format==null || format=="") {
		var generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d','MMM-d','d-MMM');
		var monthFirst=new Array('M/d/y','M-d-y','M.d.y','M/d','M-d');
		var dateFirst =new Array('d/M/y','d-M-y','d.M.y','d/M','d-M');
		var checkList=new Array(generalFormats,Date.preferAmericanFormat?monthFirst:dateFirst,Date.preferAmericanFormat?dateFirst:monthFirst);
		for (var i=0; i<checkList.length; i++) {
			var l=checkList[i];
			for (var j=0; j<l.length; j++) {
				var d=Date.parseString(val,l[j]);
				if (d!=null) { 
					return d; 
				}
			}
		}
		return null;
	}

	this.isInteger = function(val) {
		for (var i=0; i < val.length; i++) {
			if ("1234567890".indexOf(val.charAt(i))==-1) { 
				return false; 
			}
		}
		return true;
	};
	this.getInt = function(str,i,minlength,maxlength) {
		for (var x=maxlength; x>=minlength; x--) {
			var token=str.substring(i,i+x);
			if (token.length < minlength) { 
				return null; 
			}
			if (this.isInteger(token)) { 
				return token; 
			}
		}
	return null;
	};
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var year=new Date().getFullYear();
	var month=1;
	var date=1;
	var hh=0;
	var mm=0;
	var ss=0;
	var ampm="";
	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
		}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { 
				x=4;y=4; 
			}
			if (token=="yy") { 
				x=2;y=2; 
			}
			if (token=="y") { 
				x=2;y=4; 
			}
			year=this.getInt(val,i_val,x,y);
			if (year==null) { 
				return null; 
			}
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { 
					year=1900+(year-0); 
				}
				else { 
					year=2000+(year-0); 
				}
			}
		}
		else if (token=="MMM" || token=="NNN"){
			month=0;
			var names = (token=="MMM"?(Date.monthNames.concat(Date.monthAbbreviations)):Date.monthAbbreviations);
			for (var i=0; i<names.length; i++) {
				var month_name=names[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					month=(i%12)+1;
					i_val += month_name.length;
					break;
				}
			}
			if ((month < 1)||(month>12)){
				return null;
			}
		}
		else if (token=="EE"||token=="E"){
			var names = (token=="EE"?Date.dayNames:Date.dayAbbreviations);
			for (var i=0; i<names.length; i++) {
				var day_name=names[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
				}
			}
		}
		else if (token=="MM"||token=="M") {
			month=this.getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){
				return null;
			}
			i_val+=month.length;
		}
		else if (token=="dd"||token=="d") {
			date=this.getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){
				return null;
			}
			i_val+=date.length;
		}
		else if (token=="hh"||token=="h") {
			hh=this.getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){
				return null;
			}
			i_val+=hh.length;
		}
		else if (token=="HH"||token=="H") {
			hh=this.getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){
				return null;
			}
			i_val+=hh.length;
		}
		else if (token=="KK"||token=="K") {
			hh=this.getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>11)){
				return null;
			}
			i_val+=hh.length;
			hh++;
		}
		else if (token=="kk"||token=="k") {
			hh=this.getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>24)){
				return null;
			}
			i_val+=hh.length;
			hh--;
		}
		else if (token=="mm"||token=="m") {
			mm=this.getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){
				return null;
			}
			i_val+=mm.length;
		}
		else if (token=="ss"||token=="s") {
			ss=this.getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){
				return null;
			}
			i_val+=ss.length;
		}
		else if (token=="a") {
			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {
				ampm="AM";
			}
			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {
				ampm="PM";
			}
			else {
				return null;
			}
			i_val+=2;
		}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {
				return null;
			}
			else {
				i_val+=token.length;
			}
		}
	}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { 
		return null; 
	}
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ 
				return null; 
			}
		}
		else { 
			if (date > 28) { 
				return null; 
			} 
		}
	}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { 
			return null; 
		}
	}
	// Correct hours value
	if (hh<12 && ampm=="PM") {
		hh=hh-0+12; 
	}
	else if (hh>11 && ampm=="AM") { 
		hh-=12; 
	}
	return new Date(year,month-1,date,hh,mm,ss);
}

// Check if a date string is valid
Date.isValid = function(val,format) {
	return (Date.parseString(val,format) != null);
}

// Check if a date object is before another date object
Date.prototype.isBefore = function(date2) {
	if (date2==null) { 
		return false; 
	}
	return (this.getTime()<date2.getTime());
}

// Check if a date object is after another date object
Date.prototype.isAfter = function(date2) {
	if (date2==null) { 
		return false; 
	}
	return (this.getTime()>date2.getTime());
}

// Check if two date objects have equal dates and times
Date.prototype.equals = function(date2) {
	if (date2==null) { 
		return false; 
	}
	return (this.getTime()==date2.getTime());
}

// Check if two date objects have equal dates, disregarding times
Date.prototype.equalsIgnoreTime = function(date2) {
	if (date2==null) { 
		return false; 
	}
	var d1 = new Date(this.getTime()).clearTime();
	var d2 = new Date(date2.getTime()).clearTime();
	return (d1.getTime()==d2.getTime());
}

// Format a date into a string using a given format string
Date.prototype.format = function(format) {
	format=format+"";
	var result="";
	var i_format=0;
	var c="";
	var token="";
	var y=this.getYear()+"";
	var M=this.getMonth()+1;
	var d=this.getDate();
	var E=this.getDay();
	var H=this.getHours();
	var m=this.getMinutes();
	var s=this.getSeconds();
	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
	// Convert real date parts into formatted versions
	var value=new Object();
	if (y.length < 4) {
		y=""+(+y+1900);
	}
	value["y"]=""+y;
	value["yyyy"]=y;
	value["yy"]=y.substring(2,4);
	value["M"]=M;
	value["MM"]=Date.LZ(M);
	value["MMM"]=Date.monthNames[M-1];
	value["NNN"]=Date.monthAbbreviations[M-1];
	value["d"]=d;
	value["dd"]=Date.LZ(d);
	value["E"]=Date.dayAbbreviations[E];
	value["EE"]=Date.dayNames[E];
	value["H"]=H;
	value["HH"]=Date.LZ(H);
	if (H==0){
		value["h"]=12;
	}
	else if (H>12){
		value["h"]=H-12;
	}
	else {
		value["h"]=H;
	}
	value["hh"]=Date.LZ(value["h"]);
	value["K"]=value["h"]-1;
	value["k"]=value["H"]+1;
	value["KK"]=Date.LZ(value["K"]);
	value["kk"]=Date.LZ(value["k"]);
	if (H > 11) { 
		value["a"]="PM"; 
	}
	else { 
		value["a"]="AM"; 
	}
	value["m"]=m;
	value["mm"]=Date.LZ(m);
	value["s"]=s;
	value["ss"]=Date.LZ(s);
	while (i_format < format.length) {
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
		}
		if (typeof(value[token])!="undefined") { 
			result=result + value[token]; 
		}
		else { 
			result=result + token; 
		}
	}
	return result;
}

// Get the full name of the day for a date
Date.prototype.getDayName = function() { 
	return Date.dayNames[this.getDay()];
}

// Get the abbreviation of the day for a date
Date.prototype.getDayAbbreviation = function() { 
	return Date.dayAbbreviations[this.getDay()];
}

// Get the full name of the month for a date
Date.prototype.getMonthName = function() {
	return Date.monthNames[this.getMonth()];
}

// Get the abbreviation of the month for a date
Date.prototype.getMonthAbbreviation = function() { 
	return Date.monthAbbreviations[this.getMonth()];
}

// Clear all time information in a date object
Date.prototype.clearTime = function() {
  this.setHours(0); 
  this.setMinutes(0);
  this.setSeconds(0); 
  this.setMilliseconds(0);
  return this;
}

// Add an amount of time to a date. Negative numbers can be passed to subtract time.
Date.prototype.add = function(interval, number) {
	if (typeof(interval)=="undefined" || interval==null || typeof(number)=="undefined" || number==null) { 
		return this; 
	}
	number = +number;
	if (interval=='y') { // year
		this.setFullYear(this.getFullYear()+number);
	}
	else if (interval=='M') { // Month
		this.setMonth(this.getMonth()+number);
	}
	else if (interval=='d') { // Day
		this.setDate(this.getDate()+number);
	}
	else if (interval=='w') { // Weekday
		var step = (number>0)?1:-1;
		while (number!=0) {
			this.add('d',step);
			while(this.getDay()==0 || this.getDay()==6) { 
				this.add('d',step);
			}
			number -= step;
		}
	}
	else if (interval=='h') { // Hour
		this.setHours(this.getHours() + number);
	}
	else if (interval=='m') { // Minute
		this.setMinutes(this.getMinutes() + number);
	}
	else if (interval=='s') { // Second
		this.setSeconds(this.getSeconds() + number);
	}
	return this;
}


/*************************************************************/


/**************************************************************

	Script		: Element
	Version		: 1.0
	Authors		: Aaron Newton
	Desc		: Extends the <Element> prototype.

**************************************************************/


Element.extend({
/*	Property: getDimensions
		Returns width and height for element; if element is not visible the element is
		cloned off screen, shown, measured, and then removed.
		
		Returns:
		An object with .width and .height defined as integers.
		
		Example:
		>$(id).getDimensions()
		> > {width: #, height: #}
	*/
	getDimensions: function() {
		var w = 0;
		var h = 0;
		try { //safari sometimes crashes here, so catch it
			w = this.getStyle('width').toInt();
			h = this.getStyle('height').toInt();
		}catch(e){}
		if((w == 0 || $type(w) != 'number')||(h == 0 || $type(h) != 'number')){
			var holder = new Element('div').setStyles({
				'position':'absolute',
				'top':'-1000px',
				'left':'-1000px'
			}).injectAfter(this);
			var clone = this.clone().injectInside(holder).show();
			w = clone.offsetWidth;
			h = clone.offsetHeight;
			holder.remove();
		}
		return {width: w, height: h, x: w, y: h};
	},
/*	Property: setPosition
		Sets the location of an element relative to another (defaults to the document body).
		
		Note:
		The element must be absolutely positioned (if it isn't, this method will set it to be);
		
		Arguments:
		options - a key/value object with options
		
		Options:
		relativeTo - (element) the element relative to which to position this one; defaults to document.body.
		position - (string) the aspect of the relativeTo element that this element should be positioned. Options are 'upperRight', 'upperLeft', 'bottomLeft', 'bottomRight', and 'center' (the default). With the exception of center, all other options will make the upper right corner of the positioned element = the specified corner of the relativeTo element. 'center' will make the center point of the positioned element = the center point of the relativeTo element.
		offset - (object) x/y coordinates for the offset (i.e. {x: 10, y:100} will move it down 100 and to the right 10). Negative values are allowed.
		smoothMove - (boolean) move the element to the new position using <Fx.Styles>; defaults to false.
		effectOptions - (object) options object for <Fx.Styles>, optional
		returnPos - (boolean) don't move the element, but instead just return the position object ({top: '#', left: '#'}); defaults to false
		
	*/
	setPosition: function(options){
		options = Object.extend({
			relativeTo: document.body,
			position: 'center',
			offset: {x:0,y:0},
			smoothMove: false,
			effectOptions: {},
			returnPos: false
		}, options || {});
		
		this.setStyle('position', 'absolute');
		var rel = $(options.relativeTo);
		var top = (rel == document.body)?window.getScrollTop():rel.getTop();
		if (top < 0) top = 0;
		var left = (rel == document.body)?window.getScrollLeft():rel.getLeft();
		if (left < 0) left = 0;
		var dim = this.getDimensions();
		var pos = {};
		var prefY = options.offset.y.toInt();
		var prefX = options.offset.x.toInt();
		switch(options.position) {
			case 'upperLeft':
				pos = {
					'top':(top + prefY) + 'px',
					'left':(left + prefX) + 'px'
				};
				break;
			case 'upperRight':
				pos = {
					'top':(top + prefY) + 'px',
					'left':(left + prefX + rel.offsetWidth) + 'px'
				};
				break;
			case 'bottomLeft':
				pos = {
					'top':(top + prefY + rel.offsetHeight) + 'px',
					'left':(left + prefX) + 'px'
				};
				break;
			case 'bottomRight':
				pos = {
					'top':(top + prefY + rel.offsetHeight) + 'px',
					'left':(left + prefX + rel.offsetWidth) + 'px'
				};
				break;
			default: //center
				var finalTop = top + (((rel == document.body)?window.getHeight():rel.offsetHeight)/2) - (dim.height/2) + prefY;
				var finalLeft = left + (((rel == document.body)?window.getWidth():rel.offsetWidth)/2) - (dim.width/2) + prefX;
				pos = {
					'top': ((finalTop >= 0)?finalTop:0) + 'px',
					'left': ((finalLeft >= 0)?finalLeft:0) + 'px'
				};
				break;
		}
		if(options.returnPos) return pos;
		if(options.smoothMove && this.effects) this.effects(options.effectOptions).start(pos);
		else this.setStyles(pos);
		return this;
	},

/*	Property: visible
		Returns a boolean; true = visible, false = not visible.
		
		Example:
		>$(id).visible()
		> > true | false	*/
	visible: function() {
		return this.getStyle('display') != 'none';
	},
/*	Property: toggle
		Toggles the state of an element from hidden (display = none) to 
		visible (display = what it was previously or else display = block)
		
		Example:
		> $(id).toggle()
	*/
	toggle: function() {
		return this[this.visible() ? 'hide' : 'show']();
	},
/*	Property: hide
		Hides an element (display = none)
		
		Example:
		> $(id).hide()
		*/
	hide: function() {
		this.originalDisplay = this.getStyle('display'); 
		this.setStyle('display','none');
		return this;
	},
/*	Property: smoothHide
		Transitions the height, opacity, padding, and margin (but not border) from their current height to zero, then set's display to none and resets the height, opacity, etc. back to their original values.

		Arguments:
		effectOptions - options object to be passed along to Fx.Styles.
	*/
	smoothHide: function(effectOptions){
		if(this.getStyle('display') != 'none'){
			var styles = this.getStyles('padding-top', 'padding-bottom', 'margin-top', 
				'margin-bottom', 'border-top-width', 'border-bottom-width');
			styles.height = this.offsetHeight-styles['padding-top'].toInt()-styles['padding-bottom'].toInt()-
				styles['border-top-width'].toInt()-styles['border-bottom-width'].toInt()+"px";
			var zero = {height: '0px', opacity: 0};
			$each(styles, function(style, index, name){ zero[name] = 0; });
			this.effects(effectOptions||{}).start(zero).chain(function(){
				this.setStyles(styles).setStyle('display','none');
			}.bind(this));
		}
	},
/*	Property: smoothShow
		Sets the display of the element to opacity: 0 and display: block, then transitions the height, opacity, padding, and margin (but not border) from zero to their proper height.
		
		Arguments:
		effectOptions - options object to be passed along to Fx.Styles.
		heightOverride - transition to this heigh instead of the offsetHeight of the element.
	*/
	smoothShow: function(effectOptions, heightOverride){
		if(this.getStyle('display') == "none" || 
			 this.getStyle('visiblity') == "hidden" || 
			 this.getStyle('opacity')==0){
			//toggle display, but hide it
			this.setStyles({ 'display':'block', 'opacity':0 });
			var h = heightOverride || this.offsetHeight;
			var styles = Object.extend({opacity: 1},
				this.getStyles('padding-top', 'padding-bottom', 'margin-top', 
					'margin-bottom', 'border-top-width', 'border-bottom-width'));
			styles.height = h-styles['padding-top'].toInt()-styles['padding-bottom'].toInt()-
				styles['border-top-width'].toInt()-styles['border-bottom-width'].toInt()+"px";
			var zero = { height: '0px', opacity: 0 };
			$each(styles, function(style, index, name){ zero[name] = 0; });
			this.setStyles(zero).effects(effectOptions||{}).start(styles);
		}
	},
/*	Property: show
		Shows an element (display = what it was previously or else display = block)
		
		Example:
		>$(id).show() */
	show: function(display) {
		this.originalDisplay = (this.originalDisplay=="none")?'block':this.originalDisplay;
		this.setStyle('display',(display || this.originalDisplay || 'block'));
		return this;
	},
/*	Property: cleanWhitespace
		Removes all empty text nodes from an element and its children
		
		Example:
		> $(id).cleanWhitespace()	*/
	cleanWhitespace: function() {
		$A(this.childNodes).each(function(node){
			if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) node.parentNode.removeChild(node);
		});
		return this;
	},
/*	Property: find
		Returns an element from the node's array (such as parentNode), deprecated (left over from Prototype.lite).
		
		Arguments:
		what - the value you wish to find (such as 'parentNode')

		Example:
		> $(id).find(parentNode)
	*/
	find: function(what) {
		var element = this[what];
		while (element.nodeType != 1) element = element[what];
		return element;
	},
/*	Property: replace
		Replaces an html element with the html passed in.
		
		Arguments:
		html - the html with which to replace the node.
		evalScripts - (boolean; optional) evaluate javascript in the new node. defaults to true.
		
		Example:
		>$(id).replace(myHTML) */
	replace: function(html, evalScripts) {
		if (this.outerHTML) {
			this.outerHTML = html.stripScripts();
		} else {
			var range = this.ownerDocument.createRange();
			range.selectNodeContents(this);
			this.parentNode.replaceChild(
				range.createContextualFragment(html.stripScripts()), this);
		}
		if($pick(evalScripts, true)) html.evalScripts.delay(10, html);
	},
/*	Property: empty
		Returns a boolean: true = the Node is empty, false, it isn't.
		
		Example:
		> $(id).empty
		> true (the node is empty) | false (the node is not empty)
	*/
	empty: function() {
		return !!this.innerHTML.match(/^\s*$/);
	},
	/*	Property: getOffsetHeight
			Returns the offset height of an element, deprecated.
			You should instead use <Element.getStyle>('height')
			or just Element.offsetHeight.
			
			Example:
			> $(id).getOffsetHeight()
		*/
	getOffsetHeight: function(){ return this.offsetWidth; },
	/*	Property: getOffsetWidth
			Returns the offset width of an element, deprecated.
			You should instead use <Element.getStyle>('width')
			or just Element.offsetWidth.
			
			Example:
			> $(id).getOffsetWidth()
		*/
	getOffsetWidth: function(){ return this.offsetWidth; }
});

/*************************************************************/



/**************************************************************

	Script		: Inline Popup
	Version		: 1.1
	Authors		: Samuel birch
	Desc		: A floating div that can be aligned to an element.

**************************************************************/

var InlinePopup = new Class({
	
	getOptions: function(){
		return {
			id: 'InlinePopup_'+new Date().getTime(),
			onDisplay: Class.empty,
			onClose: Class.empty,
			closeClassName: 'closePopup',
			content: '',
			zIndex: 10000,
			className: '',
			position: 'center', //center, corner == upperLeft, upperRight, bottomLeft, bottomRight
			offset: {x:0,y:0},
			relativeTo: document.body, 
			width: 'auto',
			height: 'auto',
			shim: {width:0,height:0,offsetX:0,offsetY:0},
			
			fade: true,
			fadeDuration: 150,
			fadeTransition: Fx.Transitions.sineInOut
		};
	},

	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		
		if(!$(this.options.id)) {
			this.win = new Element('div').setProperty('id',	this.options.id).addClass(this.options.className).setStyles({
				display:'none',
				position:'absolute'
			}).injectInside(document.body);
		} else this.win = $(this.options.id);
		this.win.setStyle('zIndex',this.options.zIndex);
		if(this.options.width && $type(this.options.width.toInt())=="number") this.win.setStyle('width', this.options.width.toInt() + 'px');
		if(this.options.height && $type(this.options.height.toInt())=="number") this.win.setStyle('height', this.options.height.toInt() + 'px');
		//
		if(this.options.content) this.setContent(this.options.content);
		//
		this.shim = new Element('iframe').setStyles({
			display:'none',
			position: 'absolute',
			zIndex: this.options.zIndex-1,
			border: '0px',
			width: this.win.getStyle('width'),
			height: this.win.getStyle('height')
		}).setProperties({
			id: this.options.id+'_shim',
			frameBorder:'0px',
			scrolling:'no',
			src:'#'
		}).injectAfter(this.win);
	},
	
	setContent: function(html) {
		if($type(html) == "string") {
			this.win.setHTML(html);
		}else if ($(html)) {
			this.win.adopt(html);
			this.win.setStyle('width', html.getStyle('width'));
			this.win.setStyle('height', html.getStyle('height'));
		}
		this.win.getElements('.'+this.options.closeClassName).each(function(el){
			el.addEvent('click', this.hide.bind(this));
		}, this);
	},
	
	show: function(){
		this.fireEvent('onDisplay');
		if(!this.positioned) this.position();
		if(this.options.fade) {
			this.fadeIn();
		}else{
			this.win.setStyle('display','block');
			this.shim.setStyle('display','block');
		}
	},
	
	hide: function(){
		this.fireEvent('onClose');
		if(this.options.fade) {
			this.fadeOut();
		}else{
			this.win.setStyle('display','none');
			this.shim.setStyle('display','none');
		}
	},
	
	position: function(){
		this.positioned = true;
		this.win.setPosition({
			relativeTo: this.options.relativeTo,
			position: this.options.position,
			offset: this.options.offset
		});
		this.shim.setStyles({
			top: this.win.getStyle('top'),
			left: this.win.getStyle('left')
		});
	},
	
	fadeIn: function(){
		var winFx = new Fx.Style(this.win, 'opacity', {
			transition: this.options.fadeTransition, 
			duration: this.options.fadeDuration
		}).set(0);
		var shimFx = new Fx.Style(this.shim, 'opacity', {
			transition: this.options.fadeTransition, 
			duration: this.options.fadeDuration
		}).set(0);
		
		this.win.setStyle('display','block');
		this.shim.setStyle('display','block');
		
		winFx.start(0,1);
		shimFx.start(0,1);
	},
	
	fadeOut: function(){
		var winFx = new Fx.Style(this.win, 'opacity', {
			transition: this.options.fadeTransition, 
			duration: this.options.fadeDuration
		});
		var shimFx = new Fx.Style(this.shim, 'opacity', {
			transition: this.options.fadeTransition, 
			duration: this.options.fadeDuration
		});
		
		winFx.start(1,0);
		shimFx.start(1,0);
	}
	
});
InlinePopup.implement(new Options);
InlinePopup.implement(new Events);

/*************************************************************/

/**************************************************************

	Script		: Morph
	Version		: 1.0
	Authors		: Valerio Proietti
	Desc		: Morphs from one class to another

**************************************************************/

Element.extend({
	morph: function(className){
		new Fx.Morph(this).start(className);
	}
});

Fx.Morph = Fx.Styles.extend({
 
	start: function(className){
 
		var to = {};
 
		$each(document.styleSheets, function(style){
			var rules = style.rules || style.cssRules;
			$each(rules, function(rule){
				if (!rule.selectorText.test('\.' + className + '$')) return;
				Fx.CSS.Styles.each(function(style){
					if (!rule.style || !rule.style[style]) return;
					var ruleStyle = rule.style[style];
					to[style] = (style.test(/color/i) && ruleStyle.test(/^rgb/)) ? ruleStyle.rgbToHex() : ruleStyle;
				});
			});
		});
		return this.parent(to);
	}
 
});
 
Fx.CSS.Styles = ["backgroundColor", "backgroundPosition", "color", "width", "height", "left", "top", "bottom", "right", "fontSize", "letterSpacing", "lineHeight", "textIndent", "opacity"];
 
Fx.CSS.Styles.extend(Element.Styles.padding);
Fx.CSS.Styles.extend(Element.Styles.margin);
 
Element.Styles.border.each(function(border){
	['Width', 'Color'].each(function(property){
		Fx.CSS.Styles.push(border + property);
	});
});

/*************************************************************/
/**************************************************************

	Script		: Overlay
	Version		: 1.0
	Authors		: Samuel birch
	Desc		: Covers the window with a semi-transparent layer.

**************************************************************/

var Overlay = new Class({
	
	getOptions: function(){
		return {
			colour: '#000',
			opacity: 0.7,
			zIndex: 1,
			container: document.body
		};
	},

	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		
		this.options.container = $(this.options.container);
		
		this.overlay = new Element('div').setProperty('id', 'Overlay').setStyles({
			position: 'absolute',
			left: '0px',
			top: '0px',
			width: '100%',
			zIndex: this.options.zIndex,
			backgroundColor: this.options.colour
		}).injectInside(this.options.container);
		this.fade = new Fx.Style(this.overlay, 'opacity').set(0);
		this.position();
		
		window.addEvent('resize', this.position.bind(this));
	},
	
	position: function(){ 
		if(this.options.container == document.body){ 
			var h = window.getScrollHeight()+'px'; 
			this.overlay.setStyles({top: '0px', height: h}); 
		}else{ 
			var myCoords = this.options.container.getCoordinates(); 
			this.overlay.setStyles({
				top: myCoords.top+'px', 
				height: myCoords.height+'px', 
				left: myCoords.left+'px', 
				width: myCoords.width+'px'
			}); 
		} 
	},
	
	show: function(){
		this.fade.start(0,this.options.opacity);
	},
	
	hide: function(){
		this.fade.start(this.options.opacity,0);
	}
	
});
Overlay.implement(new Options);

/*************************************************************/


/**************************************************************

	Script		: URL Parser
	Version		: 1.0
	Authors		: Steven Levithan
	Desc		: Splits any well-formed URL

**************************************************************/

function parseUrl(sourceUrl){
    var urlPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
    var urlParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUrl);
    var url = {};
    
    for(var i = 0; i < 10; i++){
        url[urlPartNames[i]] = (urlParts[i] ? urlParts[i] : "");
    }
    
    // Always end directoryPath with a trailing backslash if a path was present in the source URI
    // Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
    if(url.directoryPath.length > 0){
        url.directoryPath = url.directoryPath.replace(/\/?$/, "/");
    }
    
    return url;
}

/*************************************************************/


/**************************************************************

	Script		: PNG Fix
	Version	: 1.8
	Authors	: Aaron Newton
	Desc		: make transparent pngs show up correctly in IE

**************************************************************/

function fixPNG(myImage) 
{
	try {
		if (window.ie6){
			myImage = $(myImage);
			var vis = myImage.getStyle('display') != 'none';
			if(!vis) myImage.setStyle('display','block');
			var width = $(myImage).offsetWidth;
			var height = $(myImage).offsetHeight;
			if(!vis) myImage.hide();
			var replacement = new Element('span', {
				id:(myImage.id)?myImage.id:'',
				'class':(myImage.className)?myImage.className:'',
				title:(myImage.title)?myImage.title:(myImage.alt)?myImage.alt:'',
				styles: {
					display: 'inline-block',
					width: width,
					height: height,
					filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader (src='" 
						+ myImage.src + "', sizingMethod='scale');"
				},
				src: myImage.src
			});
			if(myImage.style.cssText) {
				try {
					var styles = {};
					var s = myImage.style.cssText.split(';');
					s.each(function(style){
						var n = style.split(':');
						styles[n[0]] = n[1];
					});
					replacement.setStyle(styles);
				} catch(e){ dbug.log('fixPNG1: ', e)}
			}
			if(replacement.cloneEvents) replacement.cloneEvents(myImage);
			myImage.replaceWith(replacement);
		}
	} catch(e) {dbug.log('fixPNG2: ', e)}
};
if(window.ie6) window.addEvent('domready', function(){$$('img.fixPNG').each(function(png){fixPNG(png)});});

/*************************************************************/

/**************************************************************

	Script		: Modal Box
	Version		: 1.0
	Authors		: Samuel birch
	Desc		: Modal style dialog.

**************************************************************/

var ModalBox = new Class({
	
	getOptions: function(){
		return {
			yesFunction: false,
			noFunction: false,
			content: '',
			yesLabel: 'YES',
			noLabel: 'NO',
			buttonClass: 'modalButton',
			className: 'modalBox',
			contentClass: 'modalContent'
		};
	},

	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		
		this.overlay = new Overlay();
		
		this.container = new Element('div').addClass(this.options.className);
		
		this.content = new Element('div').addClass(this.options.contentClass).setHTML(this.options.content).injectInside(this.container);
		
		this.yesButton = new Element('input').setProperties({
			type: 'button',
			value: this.options.yesLabel
		}).addClass(this.options.buttonClass).injectInside(this.container);
		
		this.noButton = new Element('input').setProperties({
			type: 'button',
			value: this.options.noLabel
		}).addClass(this.options.buttonClass).injectInside(this.container);
		
		this.popup = new InlinePopup({content: this.container});
		
		this.yesButton.addEvent('click', this.close.bind(this,'yes'));
		this.noButton.addEvent('click', this.close.bind(this,'no'));
	},
	
	close: function(button){
		if(button == 'yes'){
			if(this.options.yesFunction){
				this.options.yesFunction();
			}
		}else{
			if(this.options.noFunction){
				this.options.noFunction();
			}
		}
		this.overlay.hide();
		this.popup.hide();
	},
	
	open: function(){
		this.overlay.show();
		this.popup.show();
	}
	
});
ModalBox.implement(new Options);
ModalBox.implement(new Events);

/*************************************************************/
