/*
Sets a Browser.ready variable when the load event is first fired
Useful for telling if you should add a load event or simply execute some code
Particularly useful when figuring sizes which doesn't really work reliably ondomready
*/
window.addEvent('load', function() {
	Browser.ready = true;
});


/*
The binds class mutator that's been floating around
I check if it's been initialized because a lot of people have likely already included this in their own libraries
*/
if (!Class.Mutators.Binds) {
	Class.Mutators.Binds = function(self, methods) {
		$splat(methods).each(function(method){
			var fn = self[method];
			self[method] = function(){
				return fn.apply(self, arguments);
			};
		});
	};
}


Element.implement({
	
	/*
	Centers an element vertically within its parent by adjusting the top margin
	*/
	verticalAlign: function() {	
		var parentSize = this.getParent().getSize();
		var thisSize = this.getSize();
		
		if (thisSize.y < parentSize.y) {
			this.setStyle('margin-top', (parentSize.y - thisSize.y) / 2);
		}
	},
	
	/*
	Given a suffix string, preloads an image from the same folder as the original image, and adds rollover events to the element
	
	ACCEPTS:
		suffix (string): String such as '-over' to insert just before the file extension
	
	USAGE:
		$$('#menu img').rollover('-over');
	*/
	addRollover: function(suffix) {	
		// Split the image src
		var origSrc = this.get('src');
		var splitSrc = origSrc.split('.');
		
		// Preload the image using the affix string
		var overImg = new Image();
		overImg.src = splitSrc[0] + suffix + '.' + splitSrc[1];
		
		// Set rollover events
		this.set({
			events: {
				mouseenter: function() {
					this.set('src', overImg.src);
				},
				mouseleave: function() {
					this.set('src', origSrc);
				}
			}
		});
	}
	
});


/*
Creates an image map and allows adding of areas
Allows adding of properties (styles, events, etc) to all areas

USAGE:
	var map = new imageMap('test');
	
	var area = map.addArea({
		shape: 'rect',
		coords: '221,68,263,174'
	});
*/
var ImageMap = new Class({
	
	/*
	Creates an image map, automatically associates it with an image using a timestamp, and injects it at the end of the document body
	
	ACCEPTS:
		* image (string or element): Id of the image to associate the image map with
		properties (obejct): Properties to apply to the image map tag
	*/
	initialize: function(image, properties) {
		var time = $time();
		
		$(image).set({
			usemap: '#map'+time
		});
		
		this.imageMap = new Element('map', {
			name: 'map'+time
		}).inject(document.body);
		
		if (properties) this.imageMap.set(properties);
	},
	
	/*
	Adds an area to the existing map
	
	ACCEPTS:
		properties (object): Properties to apply to the area tag
	RETURNS:
		area (element)
	*/
	addArea: function(properties) {
		var area = new Element('area', properties).inject(this.imageMap);
		return area;
	},
	
	/*
	Sets properties for all area tags within the image map
	
	ACCEPTS:
		properties (object): Properties to apply to all area tags
	*/
	setAll: function(properties) {
		this.imageMap.getChildren('area').set(properties);
	}
	
});


/*
Positions passed selector elements absolutely within the container element, and hides all but the first child element
Sets the height of all elements to the height of the largest
Allows for showing of a passed element and hiding of all other elements

USAGE:
	var pile = new Pile('content', 'div');
		
	$('some-button').set({
		events: {
			click: function() {
				pile.show('some-id');
			}
		}
	});
*/
var Pile = new Class({
	
	Binds: '_finalizePile',
	
	/*
	Initial setup of the pile
	
	ACCEPTS:
		* container (string|element): The container element
		* selector (string): Selector to find elements within the current element
	*/
	initialize: function(container, selector) {
		// Initialize the container element
		this.container = $(container);
		
		// Set selector variable
		this.selector = selector;
	
		// Set pile elements array
		this.pileElements = this.container.getElements(this.selector);
		
		// Set container position to relative
		this.container.setStyle('position', 'relative');
		
		// Set pile elements to a position of absolute and opacity to 0
		this.pileElements.setStyles({
			position: 'absolute',
			opacity: 0
		});
		
		// If the browser is ready, call finishPile
		if (Browser.ready)
			this._finalizePile();
		// Otherwise, add a load event to fire the function when we can determine widths and heights more reliably
		else
			window.addEvent('load', this._finalizePile);
	},
	
	/*
	Finish setting up the pile
	Should be run at page load, NOT domready
	Does not need to be called manually
	
	ACCEPTS:
		this
	*/
	_finalizePile: function() {
		// Get the container padding to adjust element positioning later
		var containerStyles = this.container.getStyles('paddingTop', 'paddingRight', 'paddingLeft');
		
		// Get the padding of the first pile element (assume all have the same padding)
		var pileStyles = this.pileElements[0].getStyles('paddingLeft', 'paddingRight');
		
		// Figure the pile element width
		var pileElementWidth = this.container.getSize().x - containerStyles.paddingLeft.toInt() - containerStyles.paddingRight.toInt() - pileStyles.paddingLeft.toInt() - pileStyles.paddingRight.toInt();
		
		// Create a variable to hold the largest height value
		var largestHeight = 0;
				
		this.pileElements.each(function(el) {
			// Get the current element's size
			var height = el.getSize().y;
			
			// Compare the largest height value with the current element's height
			largestHeight = Math.max(largestHeight, height);
			
			// Set styles for the current element
			el.setStyles({
				top: containerStyles.paddingTop,
				left: containerStyles.paddingLeft,
				width: pileElementWidth
			});
		});
				
		// Tween the container height and fade the first pile element to 1
		this.container.tween('height', largestHeight);
		this.show(this.pileElements[0]);
	},	
	
	/*
	Adds a control element which will show a particular pile item on an event
	
	ACCEPTS:
		* tabElement (string|element): The control element to add the event to
		* pileElement (string|element): The element to show when the event is triggered
		action (string): The event type to apply (Defaults to 'click')
	*/
	addTab: function(tabElement, pileElement, action) {
		// Define the default action of 'click' if necessary
		action = $pick(action, 'click');
		
		// Add the event to the tab element and pass the pile element to the show function
		$(tabElement).addEvent(action, this.show.pass(pileElement));
	},
	
	/*
	Shows the passed element and hides all others
	Does not need to be called manually, setup automatically when a tab is added
	
	ACCEPTS:
		element (string|element): The element to show
	*/
	show: function(element) {
		// Initialize the element
		element = $(element);
		
		// Get all siblings and fade them to 0
		element.getParent().getChildren().fade(0)
		
		// Fade the passed element to 1
		element.fade(1);
	}
	
});
	

/*--------------- Begin Site ------------------*/

var map = {
	
	initialize: function() {
		var highlightImgs = new Asset.images(
			['/images/map/parcel-1-over.png', '/images/map/parcel-2-over.png', '/images/map/parcel-3-over.png', '/images/map/parcel-4-over.png', '/images/map/parcel-5-over.png']
		).addClass('highlight');
		
		// Setup map and add areas
		// Global variable so we can use it in the start function
		var imgMap = new ImageMap('map');
		
		imgMap.addArea({
			shape: 'poly',
			coords: '10,21,311,287,385,288,381,275,366,255,205,55,205,18',
			alt: 'Parcel 1'
		}).store('parcel-id', 'parcel-1').store('highlight-position', '10 10');
				
		imgMap.addArea({
			shape: 'poly',
			coords: '206,18,206,52,306,178,441,126,437,69,458,18',
			alt: 'Parcel 2'
		}).store('parcel-id', 'parcel-2').store('highlight-position', '10 210');
		
		imgMap.addArea({
			shape: 'poly',
			coords: '306,179,372,262,388,251,404,249,425,248,439,241,451,228,456,210,461,190,472,173,489,160,509,153,527,151,613,139,629,132,635,124,635,111,631,90,623,79,611,75,577,80,549,82,526,79,476,70,460,67,438,68,443,126',
			alt: 'Parcel 3'
		}).store('parcel-id', 'parcel-3').store('highlight-position', '60 315');
		
		/*
		imgMap.addArea({
			shape: 'poly',
			coords: '458,18,438,68,456,68,488,72,516,79,536,81,562,81,608,75,623,77,632,93,636,110,634,127,625,134,609,139,600,141,627,199,631,206,631,213,726,213,727,17',
			alt: 'Parcel 4'
		}).store('parcel-id', 'parcel-4').store('highlight-position', '10 450');
		*/
		
		imgMap.addArea({
			shape: 'poly',
			coords: '383,287,382,278,372,264,386,253,407,248,428,246,444,235,455,221,458,197,468,178,485,162,510,152,540,149,600,140,625,192,630,206,629,213,726,213,726,284',
			alt: 'Parcel 5'
		}).store('parcel-id', 'parcel-5').store('highlight-position', '135 385');
		
		// Set a title for all area tags
		imgMap.setAll({title: 'Click for more information about this parcel'});
		
		// Setup a pile with the information divs and add the image map areas as tabs
		var pile = new Pile('content', '.parcel');
		
		imgMap.imageMap.getElements('area').each(function(el) {
			pile.addTab(el, el.retrieve('parcel-id'));
		});
		
		imgMap.imageMap.getElements('area').each(function(el) {
			var highlightImg = highlightImgs[el.retrieve('parcel-id').split('-')[1] - 1];
			var position = el.retrieve('highlight-position').split(' ');
			
			highlightImg.setStyles({
				top: position[0].toInt(),
				left: position[1].toInt()
			});
			
			el.addEvent('click', function() {
				if (Browser.ready) {
					$$('#map-container img.highlight').dispose();
					highlightImg.inject('map-container');
				}
			});
		});
	}
	
}


Element.implement({
	
	// Un-Obfuscates an email written in the following format
	// <span rel="email(seperator)address.com">whatever</span>
	// Based off David Walsh's script
	unfuscate: function(seperator) {
		new Element('a', {
			html: this.get('html'),
			href: 'mailto:' + this.get('rel').replace(seperator,'@'),  
			'class': this.get('class')
		}).replaces(this); 
	}
	
});


var site = {
	
	initialize: function() {
		// Add image rollovers to the menu
		$$('#menu img').addRollover('-over');
		
		// Unfuscate email links
		$$('.email').unfuscate('|');
		
		// Initialize the map
		if ($('map')) {
			// IE doesn't properly move the bottom background div. So I set it to move at the end of the transition here.
			if (Browser.Engine.trident) {
				$('content').set('tween', {
					onComplete: function() {
						$('bottom-bar').setStyle('bottom', 0);
					}
				});
			}
			
			// Initialize the map
			map.initialize();
		}
	},
	
	start: function() {
		// IE seems to have some issues with the bottom border....
		// So, just in case, we're going to set it here...
		if (Browser.Engine.trident)
			(function() { $('bottom-bar').setStyle('bottom', 0); }).delay(500);
	}
	
};


window.addEvent('domready', site.initialize);
window.addEvent('load', site.start);
