(function($) {

	var nav_link_manager, article_manager = null;

	var _debug = function(s) {
		try { console.debug(s); } catch(e) { }
	};

	var assert = function(val) {
		if (!val) throw 'EXCEPTION: assert: ' + this.caller.toString();
	};

	/**
	 * abstract class activation_manager
	 */
	var activation_manager_abstract_class = {
		bucket		: null,
		active_id	: '',

		/**
		 * activation_manager::init
		 */
		init : function(id) {
			_debug('activation_manager::init: ABSTRACT METHOD');
		},

		/**
		 * activation_manager::id_exists
		 */
		id_exists : function(id) {
			if (!id)				return false;
			if (!id in this.bucket)	return false;
			if (!this.bucket[id])	return false;

			return true;
		},

		/**
		 * activation_manager::activate
		 */
		activate : function(id) {
			var old_id = this.active_id;

			if (this.id_exists(id)) {
				this.active_id = id;

				if (this.bucket[id].activate)
					this.bucket[id].activate();
			}

			this.deactivate(old_id);
		},

		/**
		 * activation_manager::deactivate
		 */
		deactivate : function(id) {
			if (this.id_exists(id) && this.bucket[id].deactivate) {
				this.bucket[id].deactivate();
			}
		},

		/**
		 * activation_manager::get_current
		 */
		get_current : function() {
			if (this.active_id && this.bucket[this.active_id])
				return this.bucket[this.active_id];

			return null;
		}
	};

	/**
	 * class article_manager_class
	 *
	 * This instantiates article objects and
	 * dispatches relevant events to them.
	 */
	var article_manager_class = function(id) {
		this.init(id);
	};

	$.extend(
		article_manager_class.prototype,
		activation_manager_abstract_class,
		/** @lends {article_manager_class.prototype} */
		{
			/**
			 * article_manager::init
			 */
			init : function(id) {
				this.bucket	= { };

				// Find all article nodes and create new article objects.
				$('.article').each($.proxy(function(i, a_node) {
					var a = new article_class($(a_node));

					this.bucket[a.id] = a;

					// Activate or deactivate it depending on the initial active article.
					if (a.id == id)
						this.activate(a.id);
					else
						this.deactivate(a.id);
				}, this));

				// Listen to clicks on all nav links to show/hide articles.
				$('.nav-link').bind('click', $.proxy(this.click, this));
			},

			/**
			 * article_manager::click
			 * event-handler for nav-link click
			 */
			click : function(event) {
				var aid = event.currentTarget.fmg.article_id;

				if (this.active_id != aid)
					this.activate(aid);

				// This event should bubble.
				return true;
			}
		}
	);

	/**
	 * class nav_link_manager
	 *
	 * This instantiates nav_link objects and
	 * dispatches relevant events to them.
	 */
	var nav_link_manager_class = function(article_id) {
		this.init(article_id);
	};

	$.extend(
		nav_link_manager_class.prototype,
		activation_manager_abstract_class,
		/** @lends nav_link_manager_class.prototype */
		{
			/**
			 * nav_link_manager::init
			 */
			init : function(article_id) {
				this.bucket		= { };

				$('.nav-link').each($.proxy(function(i, item) {
					var nl = new nav_link_class($(item));
					var id = article_id + '-link';

					this.bucket[nl.id] = nl;

					nl.$.bind('click', $.proxy(this.click, this));

					if (nl.id == id)
						this.activate(nl.id);
					else
						this.deactivate(nl.id);

				}, this));
			},

			/**
			 * nav_link_manager::click
			 * event-handler for nav-link clicks
			 */
			click : function(event) {
				//assert(event.currentTarget.fmg.id);
				//assert(this.active_id);

				var nlid = event.currentTarget.fmg.id;
				if (this.active_id != nlid)
					this.activate(nlid);

				// This event should bubble.
				return false;
			}
		}
	);


	/**
	 * class article
	 *
	 * This represents an article (div.article) element.
	 * It only manages showing and hiding itself.
	 *
	 */
	var article_class = function($article) {
		this.init($article);
	};

	$.extend(
		article_class.prototype,
		/** @lends {article_class.prototype} */
		{
			$		: null,
			node	: null,
			id		: '',

			/**
			 * article::init
			 */
			init : function($article) {
				this.$			= $article;
				this.node		= this.$.get(0);
				this.node.fmg	= this;
				this.id			= this.$.attr('id');

				this.$.find('.top-link').remove();
			},

			/**
			 * article::activate
			 */
			activate : function() {
				this.$.show();
				this.$.trigger('article-activating');
			},

			/**
			 * article::deactivate
			 */
			deactivate : function() {
				this.$.hide();
				this.$.trigger('article-deactivating');
			},
		}
	);

	/**
	 * class random_child
	 *
	 */
	var random_nodes_class = function($nodes, display_msecs) {
		this.init($nodes, display_msecs);
	};

	random_nodes_class.rand = function(min, max) {
		return Math.round(Math.random() * (max - min));
	};

	$.extend(
		random_nodes_class.prototype,
		/** @lends {random_nodes_class.prototype} */
		{
			$nodes			: null,
			display_msecs	: 0,
			$curr_node		: null,
			curr_index		: -1,
			timeout_id		: -1,

			/**
			 * random_nodes::init
			 */
			init : function($nodes, display_msecs) {
				this.$nodes			= $nodes;
				this.display_msecs	= display_msecs;

				this.display_next();
			},

			display_next : function() {
				try {
					window.clearTimeout(this.timeout_id);
				}
				catch(e) { };

				var next_index = this.curr_index;
				while (next_index == this.curr_index) {
					next_index = random_nodes_class.rand(0, this.$nodes.length - 1);
				}
				//_debug('next index: ' + next_index);
				this.curr_index = next_index;

				var $new_node = $(this.$nodes.get(this.curr_index));

				if (this.$curr_node) {
					//_debug('displaying a subsequent quote');
					var $old_node	= this.$curr_node;
					this.$curr_node	= $new_node;

					$old_node.fadeOut(1000, $.proxy(function() {
						this.display_curr();
					}, this));
				}
				else {
					//_debug('displaying the first random quote');
					this.$curr_node = $new_node;
					this.display_curr();
				}
			},

			display_curr : function() {
				//_debug('displaying the current quote');
				//_debug(this.$curr_node);
				this.$curr_node.fadeIn(1000, $.proxy(function() {
					this.timeout_id = window.setTimeout($.proxy(this.display_next, this), this.display_msecs);
				}, this));
		   }
		}
	);

	/**
	 * class nav_link
	 *
	 * This represents a navigation (#nav a) element.
	 * It only handles changing its appearance on clicks.
	 *
	 */
	var nav_link_class = function($link) {
		this.init($link);
	};

	$.extend(
		nav_link_class.prototype,
		/** @lends {nav_link_class.prototype} */
		{
			$			: null,
			node		: null,
			id			: '',
			$link		: null,
			item		: null,
			title		: '',
			article_id	: '',

			/**
			 * nav_link::init
			 */
			init : function($item) {
				this.$			= $item;
				this.node		= this.$.get(0);
				this.node.fmg	= this;
				this.id			= this.$.attr('id');
				this.$link		= this.$.find('a:first');
				this.href		= this.$link.attr('href');
				this.title		= this.$link.text();
				this.article_id	= this.$link.attr('href').replace(/^#/, '');
			},

			/**
			 * nav_link::activate
			 */
			activate : function() {
				document.location = this.href;
				this.$.addClass('active');
				this.$link.addClass('active');

				$(document).find('head title:first').replaceWith(
					$(document.createElement('title')).text(this.title + " » fooMG Web Hosting")
				);
			},

			/**
			 * nav_link::deactivate
			 */
			deactivate : function() {
				this.$.removeClass('active');
				this.$link.removeClass('active');
			}
		}
	);


	$(document).ready(function() {

		var aid = window.location.hash.replace(/^#/, '');
		if (!aid || (aid == 'top'))
			aid = 'home';

		article_manager		= new article_manager_class(aid);
		nav_link_manager	= new nav_link_manager_class(aid);

		var $quotes = $('.sidebar-quote').css('display', 'none').bind('click', function(event) {
			$('#testimonials-link').click();
		});
		$('#sidebar-quotes').show();
		var random_quotes = new random_nodes_class($quotes, 30000);

		$('.hash-link').bind('click', function(event) {
			var hash = $($(event.currentTarget).find('a:first')).attr('href').replace(/^#/, '');
			if (hash)
				$('#' + hash + '-link').click();
		});

	});
})(jQuery);

