var Page = new Class((function() {
	//private variables
	var index = (location.protocol + '//' + location.hostname).replace(/\/$/, '');// + location.pathname.replace(/\/[^\/]*$/, ''),
		TITLE = document.title,
		ERROR_404 = '<div id="Page" class="narrow middle"><div class="module full"><h2>Page Not Found Error: 404</h2><p>The page you asked for could not be found.</p></div></div>';
	
	//private functions
	var needsHTML5ElmentsFix = (function() {
		var q= document.createElement("div");
		q.innerHTML="<z>i</z>";
		return q.childNodes.length!==1;
	})();
	
	var nonce = + new Date();
	
	var needsPlaceholderFix = !('placeholder' in document.createElement('input'));
	
	function fragment(content) {
		//inserting HTML5 elements into innerHTML doesn't work in IE (of course!)
		var el;
		if(needsHTML5ElmentsFix) {
			
			//replace all html5 elements to a span with a class of html5fix
			var spanned = content;
			['nav'].forEach(function(tag) {
				var re = new RegExp('<(\/?)'+tag+'([^>]*)>', 'g');
				spanned = spanned.replace(re, '<$1span htmlfix="'+tag+'"$2>');
			});
			el = new Element('div', { html: spanned }).getFirst();
			
			//after IE parses the spans, createElements of all the "fixed" elements
			el.getElements('span[htmlfix]').forEach(function(span) {
				
				var tagname = span.get('htmlfix');
				span.erase('htmlfix');
				var newEl = new Element(tagname, { html: span.innerHTML });
				newEl.replaces(span);
			});
			
			
		} else {
			
			el = new Element('div', { html: content }).getFirst();
		}
		
		if(needsPlaceholderFix) {
			//setup placeholders for Browsers that don't do it automatically
			el.getElements('input').MooPlaceholder();
		}
		
		return el;
	}
	
	function navHeight() {
		var nav = $('Nav'),
			combinedHeight =  $('Footer').getHeight() + nav.getHeight(),
			secondaryNav = nav.getElement('li.active ul');
		
		if(secondaryNav) {
			combinedHeight += secondaryNav.getHeight();
		}
		
		return combinedHeight;
	}
	
	function headerHeight() {
		return $('Header').getHeight();
	}
	
	function setActiveLinks(url) {
		//remove active state links
		$$('#Main li.active').removeClass('active');
		//set all the link active states
		$$('#Main a').forEach(function(anchor) {
			if(url && (url.indexOf(anchor.get('href')) === 0)) {
				var li = anchor.getParent('li');
				if(li) {
					li.addClass('active');
				}
			}
		});
	}
	
	function setBreadcrumbs(url) {
		var crumbs = url.split('/'),
			progressiveUrl = [],
			BC = $('Breadcrumbs');
		
		BC.set('text', '');
		
		var lastIndex = crumbs.length - 1;
		
		crumbs.forEach(function(c, index) {
			if(!c) return;
			progressiveUrl.push(c);
			var li = document.createElement('li'),
				html = '<a href="/' + progressiveUrl.join('/') + '">' + c.replace(/\-/g,' ') + '</a>';
			
			if(index < lastIndex) html += ' .';
			
			li.innerHTML = html;
			BC.appendChild(li);
		});
	}
	
	function setTitle(url) {
		var segments = url.split('/');
		if(!segments[segments.length - 1]) segments.pop();
		
		var title = segments[segments.length - 1];
		document.title = title.capitalize() + ' - ' + TITLE;
	}
	
	function centerVertically(element) {
		var el = $(element);
		
		
		//need to wait for images to load before we get real height
		var imgs = el.getElements('img, video'),
			imagesToLoad = imgs.length;
			
		imgs.forEach(function(img) {
			//check if already loaded
			if(img.height) {
				imagesToLoad--;
			}
		});
		
		if(imagesToLoad) {
			imgs.addEvent('load', function() {
				imagesToLoad--;
				if(imagesToLoad <= 0) {
					doCentering();
				}
			});
		} else {
			doCentering();
		}
		
		function doCentering() {
			el.setStyle('visibility', 'visible');
			var elCoords = el.getCoordinates();
			
			var styles = {
				position: 'absolute',
				top: ($(window).getHeight() - elCoords.height - navHeight() - headerHeight()) / 2
			};
			if(!el.hasClass('fullscreen')) {
				styles.left = ($('Content').getWidth() - elCoords.width) / 2;
			}
		
			element.setStyles(styles);
		}
		
	}
	
	//public api
	return {
		
		Implements: [Options, Events],
		
		options: {
			container: 'Content',
			fade: true
		},
		
		initialize: function(url, options) {
			this.setOptions(options);
			this.setURL(url);
		},
		
		setURL: function(fullURL) {
			this.url = fullURL;
			return this;
		}.protect(),
		
		load: function() {
			var url = this.url,
				that = this;
			
			
			//get the page thru ajax
			this.request = new Request({
				url: index + url + '.html' + (Browser.Engine.webkit ? '?'+nonce : ''),
				method: 'get',
				onSuccess: function() {
					//faggots strip out my script tags
					that.element = fragment(this.xhr.responseText);
					that.fireEvent('load');
				},
				onFailure: function(text) {
					//oh crap
					that.element = fragment(ERROR_404);
					that.fireEvent('load');
				}
			}).send();
			
			
			return this;
		},
		
		loadAndExecute: function () {
			var me = this;
			function lae_AfterLoad()
			{
				me.removeEvent('load', lae_AfterLoad);
				me.stripScripts();
				me.execute();
			}
			
			this.addEvent('load', lae_AfterLoad);
			this.load();
			return this;
		},
		
		isLoaded: function() {
			return this.request && !this.request.running;
		},
		
		insert: function() {
			//no request means we've never called load()
			if(!this.request) {
				this.load().addEvent('load', function() {
					this.insert();
					this.removeEvent('load', arguments.callee);
				});
			}
			
			//dont insert unless we're done loading
			else if(this.request.running) {
			
			//insert away
			} else {
			
				var url = this.url,
					that = this;
				
				this.stripScripts();
				this.prepareTween();
				$(this.options.container).grab(this.element);
				
				if(this.options.fade && !this.element.hasClass('no-fade') && !this.element.hasClass('no-fade-in')) {
					this.element.fade('hide').fade('in');
				} else {
					this.element.fade('show');
				}
				
				setActiveLinks(url);
				setBreadcrumbs(url);
				setTitle(url);
				this.execute();
				this.ifShouldCenter();
				if(this.options.container == 'Content') {
					this.addEvent('show', function() {
						this.ifShouldCenter();
						this.removeEvent('show', arguments.callee);
					})
				}
				
				this.fireEvent('insert');

			}
			return this;
		},
		
		prepareTween: function() {
			var that = this;
			this.element.set('tween', {
				onComplete: function() {
					that.fireEvent('show');
				}
			});
			
			return this;
		}.protect(),
		
		stripScripts: function() {
			//check for scripts/styles
			var scripts = this.scripts = [];
			var styles = this.styles = this.styles || [];
			this.element.getElements('script').forEach(function(el) {
				scripts.push(el.dispose());
			});
			
			this.element.getElements('link').forEach(function(el) {
				styles.push(el.dispose());
			});
			
			return this;
		}.protect(),
		
		execute: function() {
			var me=this;
			this.scripts.forEach(function(el) {
				ScriptManager.attemptScript({ src: el.src, text: el.get('text') || el.text });
			});
			this.styles.forEach(function(el) {
				StyleManager.attemptStyle(el, me);
			});
			this.fireEvent('execute');
			return this;
		},
		
		onCssLoaded: function (callback) { 
			if(this.cssLoaded)
			{
				callback();
			}
			else
			{
				this.addEvent('cssloaded', callback);
			}
			return this;
		
		},
		
		remove: function(callback) {
			this.fireEvent('remove');
			var el = this.element,
				that = this;
			
			
			
			if(el && (el.hasClass('no-fade-out') || el.hasClass('no-fade'))) {
				el.fade('hide');
				el.dispose();
				this.styles.forEach(function(el) {
					el.dispose();
				});
				if(typeof callback == 'function') {
					callback();
				}
			} else if(el) {
				el.fade('out').get('tween').chain(function() {
					el.dispose();
					that.styles.forEach(function(style) {
						style.dispose();
					});
					if(typeof callback == 'function') {
						callback();
					}
				});
			} else {
				if(typeof callback == 'function') {
					callback();
				}
			}
			return this;
		},
		
		unload: function() {
			this.element = this.element.destroy();
			return this;
		},
		
		ifShouldCenter: function() {
			var shouldBeCentered = this.element && (this.element.hasClass('middle') || this.element.hasClass('section-nav') || this.element.hasClass('preloader'));
			if(shouldBeCentered) {
				this.center();
			}
			return this;
		},
		
		center: function() {
			centerVertically(this.element);
			return this;
		},
		
		getURL: function() {
			return this.url;
		},
		
		getParams: function() {
			return this.params;
		},
		
		setParams: function(params) {
			this.params = params;
			this.fireEvent('paramsChanged', params || {});
			return this;
		},
		
		toElement: function() {
			return this.element;
		}
		
	};
})());