/**
 * Makes div panel expandable/collapsable
 * 
 * Required HTML markup:
 * 	<div class="expandable">
 * 		<h3>Heading</h3>
 * 		<dl>
 * 			...
 * 		</dl>
 * 	</div>
 */
var Expandable = new Class({
	
	/**
	 * Constructor
	 * @param container the HTML element to turn into an expandable
	 */
	initialize:function(container)
	{
		// Initial state
		this.state = "closed";
		
		// Setup header fade effect and hide it
		this.headerElement = container.getElement("h3");
		this.headerEffect = new Fx.Style(this.headerElement, "opacity", {duration:200});
		this.headerEffect.hide();

		// Create a control element and place on the page
		this.controlElement = new Element("span").addClass("control").appendText("Show key to symbols");
		this.controlElement.addEvent("click", this.trigger.bind(this));
		this.controlElement.injectBefore(this.headerElement);
		
		// Setup panel slide and fade effect and hide it
		this.panelElement = container.getElement("dl");
		this.fadeEffect = new Fx.Style(this.panelElement, "opacity", {duration:200});
		this.slideEffect = new Fx.Slide(this.panelElement, {duration:300, onComplete:this.complete.bind(this)});
		this.slideEffect.hide();
		this.fadeEffect.hide();
		
		// Text resize detection mechanism
		this.storedHeight = this.panelElement.scrollHeight;
		this.check.periodical(1000, this);
	},
	
	/**
	 * Triggers the open/close effect
	 */
	trigger:function()
	{
		if(this.state == "closed") this.slideEffect.toggle();
		else
		{
			this.headerEffect.start(0);
			var theSlideEffect = this.slideEffect;
			this.fadeEffect.start(0).chain( function() {
				theSlideEffect.toggle();
			});
		}
	},
	
	/**
	 * Triggered when effect is complete
	 * Shows/hides header and updates state
	 */
	complete:function()
	{
		if(this.state == "closed")
		{
			this.controlElement.innerHTML = "Hide key to symbols";
			this.fadeEffect.start(0,0.99);
			this.headerEffect.start(1);
			this.state = "open";
		}
		else
		{
			this.controlElement.innerHTML = "Show key to symbols";
			this.state = "closed";
		}
	},
	
	/**
	 * Run periodically, this resets the panel effect if its height has changed
	 */
	check:function()
	{
		// Do nothing if height is the same
		if(this.storedHeight == this.panelElement.scrollHeight) return;
		// Store new height
		this.storedHeight = this.panelElement.scrollHeight;
		// Reset slide effect
		if(this.state == "closed") this.slideEffect.hide();
		else this.slideEffect.show();
	}
	
});

/**
 * Turns a table into a "smart table"
 * Adds hover effect to rows
 * Makes rows clickable
 */
var SmartTable = new Class({
	
	/**
	 * Constructor
	 */
	initialize:function(table)
	{
		// Add the smart class tothe table for styling
		table.addClass("smart");
		
		// Get all body rows and make them smart
		var tbody = table.getElement("tbody");
		var rows = tbody.getElements("tr");
		rows.each(function(el) { new SmartRow(el); });
	}
	
});

/**
 * A smart row (see SmartTable)
 */
var SmartRow = new Class({
	
	initialize:function(row)
	{
		this.row = row;
		
		var events = {
			mouseover:this.hover.bindWithEvent(this),
			mouseout:this.hover.bindWithEvent(this)
		};
		
		// Get first link in row
		var theLink = this.row.getElement("a");
		if(theLink)
		{
			this.href = theLink.getProperty("href");
			events.click = this.click.bindWithEvent(this);
		}
		
		// Add event handlers to row
		this.row.addEvents(events);
	},
	
	/**
	 * Relocate to the href property except if a link was clicked
	 * @param event (the mootools event objec)
	 */
	click:function(event)
	{
		if($(event.target).getTag() == "a") return;
		else self.location = this.href;
	},
	
	/**
	 * Toggles the row's hover class (emulates hover pseudo-class)
	 */
	hover:function()
	{
		this.row.toggleClass("hover");
	}

});

/**
 * Adds increase/decrease controls to the page
 * Sets the font size CSS property on the body tag
 */
var TextControls = new Class({
	
	/**
	 * Constructor
	 * @param element the list to which the controls will be added
	 */
	initialize:function(element)
	{
		this.buildControls(element);
		
		// Get a reference to the body tag
		this.bodyTag = document.getElement("body");
		
		this.defaultSize = 100;
		this.min = 80;
		this.max = 120;

		this.currentSize = this.defaultSize;
		
		// Read any previously saved value
		var savedSize = Cookie.get("text_size");
		if(savedSize && savedSize.test(/[0-9]+/))
		{
			savedSize = parseInt(savedSize);
			if(savedSize >= this.min && savedSize <= this.max)
			{
				this.currentSize = savedSize;
				this.update();
			}
		}
	},
	
	/**
	 * Adds controls to page
	 * @param element the element to inject the controls into
	 */
	buildControls:function(element)
	{
		var listItem = new Element("li").addClass("text-controls");
		var label = new Element("p").appendText("Change text size").injectInside(listItem);
		var minusButton = new Element("span").appendText("-").injectInside(listItem);
		var plusButton = new Element("span").appendText("+").injectInside(listItem);
		
		// Add click events to controls
		minusButton.addEvent("click", this.decrease.bind(this));
		plusButton.addEvent("click", this.increase.bind(this));
		
		// Inject in the list
		listItem.injectInside(element);
	},
	
	/**
	 * Increases text size by 10%
	 */
	increase:function()
	{
		if(this.currentSize >= this.max) this.currentSize = this.max;
		else this.currentSize += 10;
		this.update();
	},

	/**
	 * Decreases text size by 10%
	 */
	decrease:function()
	{
		if(this.currentSize <= this.min) this.currentSize = this.min;
		else this.currentSize -= 10;
		this.update();
	},
	
	/**
	 * Resets text size to 100%
	 */
	reset:function()
	{
		this.currentSize = this.defaultSize;
		this.update();
	},
	
	/**
	 * Updates CSS and saves value to cookie
	 */
	update:function()
	{
		Cookie.set("text_size", this.currentSize, {path:"/"});
		this.bodyTag.setStyle("font-size", this.currentSize + "%");
	}
	
});

window.onDomReady( function()
{
	var siteLinks = $("header-links");
	if(siteLinks) new TextControls(siteLinks);
	
	var expandables = document.getElements("div.expandable");
	expandables.each(function(el) { new Expandable(el); });
	
	var resultsTable = document.getElement("table.results");
	if(resultsTable) new SmartTable(resultsTable);
});