String.implement({
	toElement: function() {
		return new Element('div').set('html', this).getFirst();
	}
});

var isLogoSet = false;

var Page = new Class({
	
	Implements: Options,
	
	options: {
		contentIds: ['homeContent', 'content'],
		ajaxLinks: [
		  'a[href^="/"]:not([href*="/uploads/"]):not([href*="@"])',
		  'a[href*="cairncross.com"]:not([href*="/uploads/"]):not([href*="@"])'
		],
		magicForms: ['#contactFormHolder'],
		magicFields: ['input', 'textarea', 'select'],
		logo: 'logo',
		accordion: {
			triggers: '#accordion header',
			expanders: '#accordion section'
		},
		/*accordion:{
			triggers: array('#accordion header'),
			expanders: array('#accordion section')
		},*/
		/*accordion: {
			triggers: '#accordionTwo header',
			expanders: '#accordionTwo ul'
		},*/
		activeLink: 'a.active',
		mainNav: 'mainNav'
	},
	
	initialize: function(objOptions) {
//alert("objOptions = " + objOptions);
		// set up our options
		this.setOptions(objOptions);
		
		// set up the history manager
		this.HM = new HistoryManager();
		this.HM.addEvent('page-changed', this.ajaxRequest.bind(this));
		this.HM.start();
		
		// move the logo if we're not about to do an ajax request
		if(window.location.hash.length === 0) {
			this.setActiveLink();
		}
		
		this.sharedInit();
	},
	
	// some set up functions shared by AJAX requests and "normal" requests
	sharedInit: function() {
		// WOAH Buddy... this bit of code breaks IE something fierce.
		// as much as I hate browser detection schemes this just isn't going to
		// work in IE... probably ever.
		//
		// So to clarify DO NOT RUN AJAX page requests on this website in IE
		if(!Browser.Engine.trident) {
			// set up ajax links if applicable
			if($$(this.options.ajaxLinks).length > 0) {
				this.ajaxLinks(this.options.ajaxLinks);
			}
		}
		
		// set up magic forms if applicable
		if($$(this.options.magicForms).length > 0) {
			this.magicForms(this.options.magicForms);
		}
		
		if($$(this.options.accordion.triggers).length > 0) {
			this.launchAccordion();
		}
		
		Slimbox.scanPage();
	},
	
	// return element reference to logo
	getLogo: function() {
		return $(this.options.logo);
	},
	
	// returns element reference to main nav
	getMainNav: function() {
		return $(this.options.mainNav);
	},
	
	// return element reference to "active" link
	getActiveLink: function() {
		return this.getMainNav().getElement(this.options.activeLink);
	},
	
	// return current url relative to docroot
	getCurrentPage: function() {
		var strURL;
		if(window.location.hash.length === 0) {
			strURL = window.location.pathname;
		}
		else {
			var strHash = this.HM.getHash();
			if(this.HM.options.delimeter) {
				strHash = strHash.substr(this.HM.options.delimiter.length);
			}
			var objHash = JSON.decode(decodeURIComponent(strHash));
			strURL = objHash.page;
		}
		var strRegEx = this.getLogo().getParent().get('href')+'[^/]*';
		return new RegExp(strRegEx).exec(strURL)[0];
	},
	
	// get a url relative to docroot
	getRelativeURL: function(strURL) {
		//var strRegEx = "";
		//var strRegEx = '(http\:\/\/(www\.)cairncross\.com)?(\/.*)?\/?';
		var strRegEx = '(http\:\/\/(www\.)cairncross\.com' + (strURL.indexOf('/dev') > -1 ? '\/dev' : '') + ')?(\/.*)?\/?';
		var strRelative = new RegExp(strRegEx).exec(strURL)[3];
//alert(strURL + " " + strRegEx);
		if(strRelative.lastIndexOf('/') == strRelative.length - 1) {
		  strRelative = strRelative.slice(0, -1);
		}
		return strRelative;
	},
	
	// return CSS3 selector that will select "active" link for url
	getCurrentSelector: function() {
		return 'a[href="'+this.getCurrentPage()+'"]';
	},
	
	// checks that "active" link matches url
	isActiveLinkCurrent: function(ele) {
		return ele.match(this.getCurrentSelector());
	},
	
	// return "active" link or set a new one
	setActiveLink: function() {
		var strSelector = this.getCurrentSelector();
//alert("strSelector: " + strSelector);
		var ele = this.getActiveLink();
//alert("ele: " + ele);
		if(ele) {
			if(ele.match(strSelector)) {
				return ele;
			} else {
				ele.removeClass('active');
			}
		}
		
		if(!this.isHomePage(this.getCurrentPage())) {
			ele = this.getMainNav().getElement(strSelector);
			if(ele) {
				ele.addClass('active');
			}
			this.moveLogoToActive();
		}
	},
	
	moveLogoToActive: function() {
		// now move the logo
		var eleActive = this.getActiveLink();
		var intTop = 0;
		if(eleActive) {
		  intTop = eleActive.getPosition(this.getMainNav()).y;
		}
		intTop = (!intTop || intTop < 0) ? 0 : intTop;
		var eleLogo = this.getLogo();
		if(!isLogoSet) {
			eleLogo.setStyles({
				top: intTop,
				visibility: 'visible'
			});
			isLogoSet = true;
		}
		else {
			eleLogo.tween('top', intTop);
		}
	},
	
	// determine if current page is homepage
	isHomePage: function(strURL) {
		return (strURL == this.getLogo().get('href'));
	},
	
	// make asychronous request against the server
	ajaxRequest: function(strURL) {
		this.setActiveLink();
//alert("strURL: " + strURL);
		new Request.JSON({
			url: strURL,
			onSuccess: this.renderPage.bind(this)
		}).get({ajax: true});
//alert("this: " + this.toSource());
	},
	
	renderPage: function(obj) {
//document.write("obj: " + obj.toSource());
		// set document title
		document.title = [document.title.split(' | ')[0], obj.subtitle].join(' | ');
		
		// set id for content
		var arrIds = (this.isHomePage()) ? this.options.contentIds.reverse() : this.options.contentIds;
		var ele = $(arrIds[0]);
		
		if(ele) {
			ele.set('id', arrIds[1]);
		}
		
		// set body header
		$('bodyHeader').set('html', obj.bodyHeader);
		
		// set body
		$('body').set('html', obj.body);
		
		// set page background
		if(obj.backgroundImage) {
			$('wrap').setStyle('backgroundImage', 'url('+obj.backgroundImage+')');
		} else {
			$('wrap').setStyle('backgroundImage', 'none');
		}
//document.write("obj: " + obj.toSource());
//alert("obj.subNav = " + obj.subNav);
		// set subnavigation
		if(obj.subNav) {
//alert("set subnav 1");
			// change content container's id if neccesary
			ele = $('homeContent');
			
			if(ele) {
				ele.set('id', 'content');
			}
			
			ele = $('content');
			// destroy old navigation if neccesary
			var eleOldNav = $('detailNav');
			if(eleOldNav) {
				eleOldNav.destroy();
			}
			// inject subnavigation into page
			obj.subNav.toElement().inject(ele, 'after');
		} else {
//alert("set subnav 2");
			ele = $('detailNav');
			if(ele) { ele.destroy(); }
			ele = $('content');
			if(ele) { ele.set('id', 'homeContent'); }
		}
		// I could do some fancy scrolling back to the top of the screen with
		// Fx.Scroll but it's unexpected behavior and would probably scare the
		// user.  So instead let's just cut to the top of the page on page change.
		$(document.body).scrollTo();
		// IMPORTANT!!!
		// change the value of ajaxLinks so we don't assign multiple listeners
		this.constructor({
			ajaxLinks: [
				'#body a[href^="/"]:not([href*="/uploads/"]):not([href*="@"])',
				'#body a[href*="cairncross.com"]:not([href*="/uploads/"]):not([href*="@"])',
				'#detailNav a[href^="/"]:not([href*="/uploads/"]):not([href*="@"])'
			]
		});
	},
	
	ajaxLinks: function(arrLinks) {
		var self = this;
		$$(arrLinks).addEvent('click', function(e) {
			self.HM.set('page', self.getRelativeURL(this.get('href')));
			return false;
		});
	},
	
	slider: function(intTop) {
		var ele = $(this.options.logoSlider);
		ele.tween('top', intTop);
	},
	
	magicFields: function(fields) {
		var arrFields = $$(fields);
		var eleForm = arrFields[0].getParent('ul');
		var objFormPos = eleForm.getPosition();
		var objFormSize = eleForm.getSize();
		eleForm.setStyles({
			position: 'relative',
			height: objFormSize.y,
			width: objFormSize.x
		});
		
		arrFields.each(function(element) {
			var eleParent = element.getParent('li.field');
			var objFieldPos = eleParent.getPosition();
			eleParent.setStyles({
				top: (objFieldPos.y - objFormPos.y),
				left: (objFieldPos.x - objFormPos.x)
			});
			(function() {
				this.setStyles({
					position: 'absolute'
				});
				this.fade(0, 1);
			}).delay(1000, eleParent);
			// set the parent to position relative
			var objColor = new Color(element.getStyle('backgroundColor'));
			
			element.addEvents({
				focus: function(objColor)
				{
					this.addClass('focused');
				}.bind(eleParent, [objColor]),
				blur: function(objColor)
				{
					this.removeClass('focused');
				}.bind(eleParent, [objColor])
			});
		}.bind(this));
	},
	
	// This function is the result of a braistorm about form spam.  Web spiders
	// don't usually have javascript engines built into them.  They pull the
	// html of a page but any content generated by javascript is invisible.
	// 
	// So... if we don't generate forms until the browser loads then they're
	// pretty much safe from tampering in most use case scenarios.
	magicForms: function(arrForms) {
		// call any named form builder functions
		arrForms.each(function(id) {
			var f = id.slice(1);
			if(this[f] && $(document.body).getElement(id)) {
				var eleForm = this[f]();
    		eleForm.addEvent('submit', function(objEvent) {
    		  objEvent.stop();
    			objEvent.preventDefault();
    			this.set('send', {
    				onComplete: function(response) {
    					var objJSON = JSON.decode(response);
    					if(objJSON.response === false)
    					{
    						alert(objJSON.errors.join("\n"));
    					}
    					else if(objJSON.redirect !== undefined) {
    						window.location = objJSON.redirect;
    					}
    					else
    					{
    						this.empty();
    						var eleMessage = new Element('p')
    							.addClass('message')
    								.set('html', objJSON.message);
    						eleMessage.inject(this, 'before');
    					}
    				}.bind(this)
    			});
    			this.send();
    		});
    		this.magicFields(this.options.magicFields);
			}
		}.bind(this));
	},
	
	// generating forms with javascript prevents 99.9% of form hijacking
	contactFormHolder: function() {
		var form = new Form(
			{action: this.getCurrentPage(), method: 'post', id: 'contactForm'},
			[
				['text', {name: 'fullName'}],
				['text', {name: 'email', label: 'E-Mail'}],
				['text', {name: 'phone'}],
				['textarea', {name: 'comment'}],
				['submit', {name: 'submit', value: 'Send'}]
			]
		);
		form.inject('contactFormHolder');
		return form;
	},
	
	launchAccordion: function() {
		new Fx.Accordion(
			$$(this.options.accordion.triggers),
			$$(this.options.accordion.expanders),
			{ alwaysHide: true, display: -1 }
		);
	}
});

window.addEvent('domready', function() {
	new Page();

	/*ele = document.getElementsByName('accordion');
	if(ele.length > 0){
		for(x=0; x<ele.length; x++){
			setAccordion(ele.id);
		}
	}*/
});

/*function setAccordion(ele){
	trigger = ele + ' header';
	expander =  
	new Fx.Accordion(
		
		$$(ele header),
		$$(),
		{ alwaysHide: true, display: -1 }
	);
}*/

		/*accordion: {
			triggers: '#accordionTwo header',
			expanders: '#accordionTwo ul'
		},*/
