var AjaxContent = Class.create({
	initialize: function(container) {
		
		// Get options
		this.options = Object.extend({
			waitImages:			false,
			linkClass:			null,
			urlPostfix:			'',
			catchSameUrl:		false,
			initAnchor:			false,
			useAnchor:			false,
			useAnalytics:		false,
			titlePrefix:		null,
			titleSeperator:		' | ',
			loadingDiv:			null,
			loadDelay:			800,
			
			// Callback functions
			preCallback:		null,
			postCallback:		null,
			anchorCallback:		null
		}, arguments[1] || {} );
		
		// Set member variables
		this.container = container;
		this.isRunning = false;
		this.loadTimer = null;
		this.links = [];
		this.title = null;
		this.url = null;
		
		// Bind event listeners
		this.bonClick = this.onClick.bindAsEventListener(this);
		
		// Attach any links on the main page
		this.attachLinks();
		
		// Check for an initail anchor
		if(this.options.initAnchor === true && this.options.useAnchor === true) {
			this.getAnchor(); }
	},
	
	
	/******************************************
	 *	Public functions
	 */
	
	// Place the contents of the url into this.element
	getContent: function(url) {
		
		// Don't do anything if url is blank
		if(!url) { return; }
		
		// Don't reload the same thing
		if(this.url == url && this.options.catchSameUrl === true) {
			return; }
		this.url = url;
		
		// Check isRunning
		if(this.isRunning === true) {
			return; }
		this.isRunning = true;
		
		// Call the pre callback
		if(this.options.preCallback !== null) {
			this.options.preCallback(this); }
		
		// Start a timer to perform an action on a long load time
		this.startLoad();
		
		// Start the AJAX request
		if(typeof(url) == 'string')
		{
			var request = new Ajax.Request(url + this.options.urlPostfix, {
				onSuccess: this.onSuccess.bind(this),
				onFailure: this.onFailure.bind(this)
			});
		}
		else if(url instanceof Array)
		{
			$(Builder.node('form', {action: url[0]})).request({
				method: 'post',
				parameters: url[1],
				onSuccess: this.onSuccess.bind(this),
				onFailure: this.onFailure.bind(this)
			});
		}
	},
	
	cleanLinks: function() {
		if(this.options.linkClass !== null)
		{
			// Cleanup any old links
			this.links.each(function(elem) {
				elem.stopObserving('click', this.bonClick);
			}, this);
		}
	},
	
	attachLinks: function() {
		if(this.options.linkClass !== null)
		{
			// Make an event for each link
			this.links.clear();
			$$('a.' + this.options.linkClass).each(function(elem) {
				elem.observe('click', this.bonClick);
				this.links.push(elem);
			}, this);
		}
	},
	
	getPage: function(url) {
		var pageMatch = /^(?:[^\/]*\/)*([^\.]+)\.php$/;
		var pageArray = pageMatch.exec(url);
		
		if(pageArray) {
			return pageArray[1]; }
		else {
			return null; }
	},
	
	/******************************************
	 *	Protected functions
	 */
	
	onFailure: function(req) {
		
		// Mark we have finished
		this.isRunning = false;
		
		// Cancel the load delay timer
		this.finishLoad();
			
		// Show an error
		this.displayContent('Page not found.');
			
		// Set the anchor to 'error'
		if(this.options.useAnchor === true) {
			this.setAnchor('error'); }
			
		// Send the page to analytics so we can track the ajax page changes
		if(this.options.useAnalytics === true) {
			pageTracker._trackPageview("/error.php"); }
	},
	
	onSuccess: function(req) {
		
		// Check for JSON response
		if(req.responseJSON) {
			this.displayContent(req.responseJSON); }
		
		// Check for XML response, if no XML send the text
		else if(!req.responseXML) {
			this.displayContent(req.responseText); }
		else if(!req.responseXML.documentElement) {
			this.displayContent(req.responseText); }
		
		// Else, parse the xml
		else
		{
			// Get the xml response
			var xmlRoot = req.responseXML.documentElement;
			
			// Show the content
			var contentStr = this.parseContent(xmlRoot, 'content', true);
			if(contentStr !== null) {
				this.displayContent(contentStr); }
			
			// Check for a specific title tag
			var titleTag = xmlRoot.getElementsByTagName('title');
			if(titleTag.length > 0) {
				this.title = titleTag[0].getAttribute('name'); }
			
			// Update the document title
			if(this.options.titlePrefix !== null) {
				document.title = this.options.titlePrefix + (this.title!==null?this.options.titleSeperator+this.title:''); }
		}
		
		// Get the page from the url
		var page = this.getPage(url);
		
		// Set the anchor to the current page
		if(this.options.useAnchor === true) {
			this.setAnchor(page); }
			
		// Send the page to analytics so we can track the ajax page changes
		if(this.options.useAnalytics === true) {
			pageTracker._trackPageview("/" + page); }
	},
	
	parseContent: function(xmlRoot, tagName, required)
	{
		// This check will only work in ie
		// Need to check for parseerror in firefox
		//if(xmlRoot == null) {
		//	return false; }
		
		var contentTag = xmlRoot.getElementsByTagName(tagName);
		var xmlString = "";
		
		// Write the content to the document
		if(contentTag.length > 0)
		{
			if(contentTag[0].xml)
			{
				for(node_i = 0; node_i < contentTag[0].childNodes.length; node_i++) {
					xmlString += contentTag[0].childNodes[node_i].xml; }
			}
			else
			{
				for(node_i = 0; node_i < contentTag[0].childNodes.length; node_i++) {
					xmlString += new XMLSerializer().serializeToString(contentTag[0].childNodes[node_i]); }
			}
			
			xmlString = xmlString.strip();
			if(xmlString !== "") {
				return xmlString; }
		}
		else if(required === true) {
			this.displayContent('Required tag, ' + tagName + ', not found.'); }
			
		return null;
	},
	
	// Call the success callback
	displayContent: function(text) {
		
		// Cleanup any old links
		this.cleanLinks();
		
		// Update the content
		if(this.container !== null) {
			$(this.container).update(text); }
		
		// Attach any links added to the page
		this.attachLinks();
		
		// Wait for any images to load
		if(this.options.waitImages === true && this.container !== null) {
			this.waitImages(); }
		
		// Else finish up now
		else
		{
			// Flag done
			this.isRunning = false;
			
			// Cancel the load delay timer
			this.finishLoad();
			
			// Call the post function
			if(typeof this.options.postCallback == 'function') {
				this.options.postCallback(this, text); }
		}
	},
	
	waitImages: function() {
		this.imagesAttempts = 0;
		this.imagesLoading = new PeriodicalExecuter(this.checkImages.bind(this), 0.1);
	},
	
	checkImages: function() {
		var unloaded = 0;
		$A(document.images).each(function(elem) {
			if($(elem).descendantOf(this.container) && elem.complete === false) {
				unloaded++; }
		}, this);
		
		var isLoaded = (unloaded === 0);
		if(this.imagesLoading !== null)
		{
			this.imagesAttempts++;
			if(isLoaded || this.imagesAttempts > 100)
			{
				// Stop the image load check
				this.imagesLoading.stop();
				this.imagesLoading = null;
				
				// Flag done
				this.isRunning = false;
				
				// Cancel the load delay timer
				this.finishLoad();
				
				// Call the post function
				if(typeof this.options.postCallback == 'function') {
					this.options.postCallback(); }
			}
		}
		
		return isLoaded;
	},
	
	onClick: function(event) {
		if(event) { event.stop(); }
		var element = Event.element(event);
		this.getContent(element.readAttribute('href'));
	},
	
	// Start a timer to perform an action on a long load time
	startLoad: function() {
		var div = $(this.options.loadingDiv);
		if(div !== null) {
			this.loadTimer = setTimeout(function(){div.show();}, this.options.loadDelay); }
	},
	
	// Cancel the load delay timer
	finishLoad: function() {
		if(this.loadTimer !== null)
		{
			clearTimeout(this.loadTimer);
			this.loadTimer = null;
			$(this.options.loadingDiv).hide();
		}
	},
	
	// Take an anchor from the address bar
	getAnchor: function() {
		var anchor = window.location.hash;
		var pageMatch = /^#(.+)$/;
		var pageArray = pageMatch.exec(anchor);
		
		if(pageArray)
		{
			var anchorStr = pageArray[1] + '.php';
			
			if(this.options.anchorCallback !== null) {
				this.options.anchorCallback(anchorStr); }
			
			this.getContent(anchorStr);
		}
	},
	
	// Put the page in the hash for bookmarks and navigation
	setAnchor: function(page) {
		window.location.hash = "#" + page;
	}
});