/*
Name:       Behaviour
Version:    0.1.4 (18 Juli 2011)
Company:    stadt.werk	
Author:     Finn Rudolph
Support:    rudolph@stadtwerk.org

License:    This code is licensed under a Creative Commons 
            Attribution-Noncommercial 3.0 Unported License 
            (http://creativecommons.org/licenses/by-nc/3.0/).

            You are free:
                + to Share - to copy, distribute and transmit the work
                + to Remix - to adapt the work

            Under the following conditions:
                + Attribution. You must attribute the work in the manner specified by the author or licensor 
                  (but not in any way that suggests that they endorse you or your use of the work). 
                + Noncommercial. You may not use this work for commercial purposes. 

            + For any reuse or distribution, you must make clear to others the license terms of this work.
            + Any of the above conditions can be waived if you get permission from the copyright holder.
            + Nothing in this license impairs or restricts the author's moral rights.

Credits:    This script uses the domReady function from Tanny O'Haley [1], the 
            getElementsByClass function by Dustin Diaz [2] and the fireEvent 
			function by Jehiah Czebotar [3].
 
            [1] http://tanny.ica.com/ICA/TKO/tkoblog.nsf/dx/domcontentloaded-for-browsers-part-v
            [2] http://www.dustindiaz.com/getelementsbyclass
			[3] http://jehiah.cz/archive/firing-javascript-events-properly
*/


/* Behaviour constructor */
function behaviour()
{
	/* Closure for this */
	var my = this;

	/* Initiate behaviour */
	this.init = function()
	{
		my.Resize.init();
		my.Metabox.init();
		my.Touch.init();
		my.ElementLink.init();
	};
	
	
	/* Adds  functions */
	this.ElementLink =
	{
		/* Executes once on load */
		init: function()
		{
			var links = my.Tool.getElementsByClass('listLink', 'DIV', document);
			var max = links.length, link;
			for(i=0; i<max; i++)
			{
				/* Store link in parent div element */
				link = links[i];
				if(link.firstChild)
				{
					link.parentNode.link = link.firstChild.href;
				
					/* Redirect to link on click */
					link.parentNode.onclick = function(){ location.href = this.link; };
				}
			}			
		}
	};
	
	/* Touch functions */
	this.Touch =
	{
		/* Executes once on load */
		init: function()
		{
			/* Check for touch devices (iPhone and iPod Touch) */
			if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) 
			{
				setTimeout( function(){ window.scrollTo(0, 0); }, 500);
			}
		}
	};
	
	/* Resize functions */
	this.Resize =
	{
		/* Executes once on load */
		init: function()
		{
			/* Do not add the resize behaviour on apple devices */
			var agent = navigator.userAgent;
			var appleDevice = (agent.match(/iPhone/i) || agent.match(/iPod/i) || agent.match(/iPad/i)) ? true : false;
			if(appleDevice === false)
			{
				/* Add size check event to window */
				my.Resize.addResizeEvent();
				
				/* Check size once on load - a short delay is needed */
				window.setTimeout(my.Resize.check, 50);
				
				/* Get page and foot element */
				this.page = document.getElementById('page');
				this.foot = document.getElementById('foot');
			}
		},
		
		/* Add resize event to window */
		addResizeEvent: function()
		{
			var otherFunctions = window.onresize;
			if(typeof window.onresize != 'function')
			{
				window.onresize = function()
				{
					my.Resize.check();
				};
			}
			else
			{
				window.onresize = function()
				{
					if (otherFunctions)
					{
						otherFunctions();
					}
					my.Resize.check();
				};
			}
		},
		
		/* Add resize event to window */
		check: function()
		{
			var width = document.body.clientWidth;
			
			if(width < 1000)
			{
				my.Tool.setClassName(my.Resize.page, 'small');
				my.Tool.setClassName(my.Resize.foot, 'small');
			}
			else
			{
				my.Tool.setClassName(my.Resize.page, '');
				my.Tool.setClassName(my.Resize.foot, '');
			}
		}
	};
	

	/* Metabox functions */
	this.Metabox =
	{
		activeClassName: '',
		
		/* Executes once on load */
		init: function()
		{
			/* Get metabox DOM elements */
			my.Metabox.getStructure();
			
			/* Get current hash tag */
			hash = window.location.hash;
			
			/* Add events to all metabox links */
			var max = my.Metabox.links.length;
			var i, link, height;
			for(i = 0; i < max; i++)
			{
				link = my.Metabox.links[i];
				my.Tool.addEvent(link, 'click', my.Metabox.expand);
				my.Tool.addEvent(link, 'click', my.Tool.suppressBrowserDefault);
				
				/* Expand link if the hash tag is the same */
				if('#'+link.className == hash)
				{
					my.Tool.fireEvent(link,'click');
				}
			}
		},
		
		/* Store pointers to metabox DOM elements */
		getStructure: function()
		{
			/* Get metabox div */
			this.div = document.getElementById('metabox');
			
			/* Get metabox content div */
			this.contentDiv = my.Tool.getElementsByClass('content', 'DIV', my.Metabox.div)[0];
			
			/* Get metabox menu div */
			this.menuDiv = my.Tool.getElementsByClass('menu', 'DIV', my.Metabox.div)[0];
			
			/* Get links in menu div */
			this.links = my.Metabox.menuDiv.getElementsByTagName('A');
		},
		
		/* Expand the content container */
		expand: function(element)
		{
			/* Get CSS class name of this link */
			var className = this.className;
			
			/* Set hash to current class name */
			window.location.hash = '#'+className;
			
			/* Make sure, that all elements are collapsed before a new one is expanded */
			my.Metabox.collapseActiveElement(className);
			
			/* Set this class name active */
			my.Metabox.activeClassName = className;

			/* Get content element */
			var content = my.Metabox.getContentBySameClassName(this);			
			
			/* Display the content element and expand it */
			content.style.display = 'block';
			
			/* Set new CSS class */
			className = className+' active';
			my.Tool.setClassName(this, className);
			my.Tool.setClassName(content, className);

			/* Switch expand and collapse event */
			my.Tool.removeEvent(this, 'click', my.Metabox.expand);
			my.Tool.addEvent(this, 'click', my.Metabox.collapse);
		},
		
		/* Collapse the content container */
		collapse: function()
		{
			/* Get content element */
			var content = my.Metabox.getContentBySameClassName(this);
			
			/* Hide the content element and collapse it */
			content.style.display = 'none';
			
			/* Reset CSS class */
			var className = this.className.split(' ')[0];
			my.Tool.setClassName(this, className);
			my.Tool.setClassName(content, className);
			
			/* Reset active class name globale */
			my.Metabox.activeClassName = '';
			
			/* Switch expand and collapse event */
			my.Tool.addEvent(this, 'click', my.Metabox.expand);
			my.Tool.removeEvent(this, 'click', my.Metabox.collapse);
		},
		
		/* Gets content element with same class name like the element */
		getContentBySameClassName: function(element)
		{
			/* Get classname of the element */
			var className = element.className;
			
			/* Get metabox content element with the same class name */
			return my.Tool.getElementsByClass(className, 'DIV', my.Metabox.contentDiv)[0];
		},
		
		/* Collapse the active element */
		collapseActiveElement: function(newClassName)
		{
			/* Only collapse elements that are active and not currently beeing expanded */
			var className = my.Metabox.activeClassName;
			if(className && (className !== newClassName))
			{
				/* Fire the link event of the content that should collapse */
				var link = my.Tool.getElementsByClass(className, 'A', my.Metabox.menuDiv)[0];
				my.Tool.fireEvent(link,'click');
			}
		}
	};
	
	/* Tool functions */
	this.Tool =
	{
		
		/* Suppress default browser behaviour to avoid image/text selection while dragging */
		suppressBrowserDefault: function(e)
		{
			if(e.preventDefault)
			{
				e.preventDefault();
			}
			else
			{
				e.returnValue = false;
			}
			return false;
		},
		
		/* Get rendered CSS style settings from element */
		getStyle: function(element, css)
		{
			var style = '';
			if(document.defaultView && document.defaultView.getComputedStyle)
			{
				style = document.defaultView.getComputedStyle(element, '').getPropertyValue(css);
			}
			else if(element.currentStyle)
			{
				css = css.replace(/\-(\w)/g, function (strMatch, p1){ return p1.toUpperCase(); });
				style = element.currentStyle[css];
			}
			return style;
		},
		
		/* Get DOM elements by class name - function by Dustin Diaz [2] */
		getElementsByClass: function (searchClass, tag, node) 
		{
			var classElements = [];
			var element = node.getElementsByTagName(tag);
			var max = element.length;
			var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");			
			for(var i = 0, j = 0; i < max; i++)
			{
				if(pattern.test(element[i].className))
				{
					classElements[j] = element[i];
					j++;
				}
			}
			return classElements;
		},
		
		/* Fire element events properly - function by Jehiah Czebotar [3] */
		fireEvent: function(element, event)
		{
			if (document.createEvent) 
			{
				/* The good browsers */
				var evt = document.createEvent("HTMLEvents");
				evt.initEvent(event, true, true );	/* event type, bubbling, cancelable */
				return !element.dispatchEvent(evt);
			}
			else
			{
				/* The Internet Explorer */
				var evt = document.createEventObject();
				return element.fireEvent('on'+event,evt)
			}
		},
		
		/* Set CSS class */
		setClassName: function(element, className)
		{
			if(element)
			{
				element.setAttribute('class', className);
				element.setAttribute('className', className);
			}
		},
	
		/* Add events */
		addEvent: function(obj, type, fn)
		{
			if(obj.addEventListener)
			{
				obj.addEventListener(type, fn, false);
			}
			else if(obj.attachEvent)
			{
				obj["e"+type+fn] = fn;
				obj[type+fn] = function() { obj["e"+type+fn]( window.event ); };
				obj.attachEvent( "on"+type, obj[type+fn] );
			}
		},
 
		/* Remove events */
		removeEvent: function( obj, type, fn )
		{
			if (obj.removeEventListener)
			{
				obj.removeEventListener( type, fn, false );
			}
			else if (obj.detachEvent)
			{
				/* The IE breaks if you're trying to detach an unattached event http://msdn.microsoft.com/en-us/library/ms536411(VS.85).aspx */
				if(obj[type+fn] === undefined)
				{
					alert('Tool.removeEvent » Pointer to detach event is undefined - perhaps you are trying to detach an unattached event?');
				}
				obj.detachEvent( 'on'+type, obj[type+fn] );
				obj[type+fn] = null;
				obj['e'+type+fn] = null;
			}
		}
	};
};

/* DOMContentLoaded event handler - by Tanny O'Haley [1] */
var domReadyEvent =
{
	name: "domReadyEvent",
	/* Array of DOMContentLoaded event handlers.*/
	events: {},
	domReadyID: 1,
	bDone: false,
	DOMContentLoadedCustom: null,

	/* Function that adds DOMContentLoaded listeners to the array.*/
	add: function(handler)
	{
		/* Assign each event handler a unique ID. If the handler has an ID, it has already been added to the events object or been run.*/
		if (!handler.$$domReadyID)
		{
			handler.$$domReadyID = this.domReadyID++;

			/* If the DOMContentLoaded event has happened, run the function. */
			if(this.bDone)
			{
				handler();
			}

			/* store the event handler in the hash table */
			this.events[handler.$$domReadyID] = handler;
		}
	},

	remove: function(handler)
	{
		/* Delete the event handler from the hash table */
		if (handler.$$domReadyID)
		{
			delete this.events[handler.$$domReadyID];
		}
	},

	/* Function to process the DOMContentLoaded events array. */
	run: function()
	{
		/* quit if this function has already been called */
		if (this.bDone)
		{
			return;
		}

		/* Flag this function so we don't do the same thing twice */
		this.bDone = true;

		/* iterates through array of registered functions */
		for (var i in this.events)
		{
			this.events[i]();
		}
	},

	schedule: function()
	{
		/* Quit if the init function has already been called*/
		if (this.bDone)
		{
			return;
		}

		/* First, check for Safari or KHTML.*/
		if(/KHTML|WebKit/i.test(navigator.userAgent))
		{
			if(/loaded|complete/.test(document.readyState))
			{
				this.run();
			}
			else
			{
				/* Not ready yet, wait a little more.*/
				setTimeout(this.name + ".schedule()", 100);
			}
		}
		else if(document.getElementById("__ie_onload"))
		{
			/* Second, check for IE.*/
			return true;
		}

		/* Check for custom developer provided function.*/
		if(typeof this.DOMContentLoadedCustom === "function")
		{
			/* if DOM methods are supported, and the body element exists (using a double-check
			including document.body, for the benefit of older moz builds [eg ns7.1] in which
			getElementsByTagName('body')[0] is undefined, unless this script is in the body section) */
			if(typeof document.getElementsByTagName !== 'undefined' && (document.getElementsByTagName('body')[0] !== null || document.body !== null))
			{
				/* Call custom function. */
				if(this.DOMContentLoadedCustom())
				{
					this.run();
				}
				else
				{
					/* Not ready yet, wait a little more. */
					setTimeout(this.name + ".schedule()", 250);
				}
			}
		}
		return true;
	},

	init: function()
	{
		/* If addEventListener supports the DOMContentLoaded event.*/
		if(document.addEventListener)
		{
			document.addEventListener("DOMContentLoaded", function() { domReadyEvent.run(); }, false);
		}

		/* Schedule to run the init function.*/
		setTimeout("domReadyEvent.schedule()", 100);

		function run()
		{
			domReadyEvent.run();
		}

		/* Just in case window.onload happens first, add it to onload using an available method.*/
		if(typeof addEvent !== "undefined")
		{
			addEvent(window, "load", run);
		}
		else if(document.addEventListener)
		{
			document.addEventListener("load", run, false);
		}
		else if(typeof window.onload === "function")
		{
			var oldonload = window.onload;
			window.onload = function()
			{
				domReadyEvent.run();
				oldonload();
			};
		}
		else
		{
			window.onload = run;
		}

		/* for Internet Explorer */
		/*@cc_on
			@if (@_win32 || @_win64)
			document.write("<script id=__ie_onload defer src=\"//:\"><\/script>");
			var script = document.getElementById("__ie_onload");
			script.onreadystatechange = function()
			{
				if (this.readyState == "complete")
				{
					domReadyEvent.run(); // call the onload handler
				}
			};
			@end
		@*/
	}
};

var domReady = function(handler) { domReadyEvent.add(handler); };
domReadyEvent.init();

/* Create behaviour instance when the DOM structure has been loaded */
domReady(function()
{
	var lbvBehaviour = new behaviour();
	lbvBehaviour.init();
});
