/**
 * This file is reponsible for managing the js library of classes and functions
 *
 * @author Richard Hallows
 * @author Pete Goodman
*/
var LibraryManager = {

	/**
	 * The path to the root of the site
	 *
	 * @var string path 
	 */
	path: null,
	
	/**
	 * Flag to indicate if we're in the cms or not
	 *
	 * @var bool is cms flag 
	 */
	iscms: null,
	
	/**
	 * The class of the current page
	 *
	 * @var string pageClass 
	 */
	pageClass: null,
	
	/**
	 * The id of the current page
	 *
	 * @var string pageId
	 */
	pageId: null,
	
	
	/**
	 * all javascript functions to call when the DOM of the page has loaded
	 *
	 * @var array loadEvents
	 */
	loadEvents: [],
	
	/**
	 * initialise the library manager
	 *
	 * @return void  
	 */
	initialise: function() {

		this.calculatePath();
		this.calculateState();
		
		//import either the site or cms library manager
		if (this.iscms) {
			this.require('cmslibrarymanager.js');
		} else {
			this.require('sitelibrarymanager.js');	
		}

		// add the initial on dom load event to calculate the page class and id
		this.addLoadEvent( 
			function() {
				LibraryManager.calculatePageDetails();
			}
		);
	},
	
	
	/**
	 * Calculates and sets the relative path from the js library to the root
	 *
	 * @return void  
	 */
	 calculatePath: function() {
		
		// condition : is object var already set?
		if (this.path === null) {
			
			// get path from LibraryManager javascript include string
			var scriptTags = document.getElementsByTagName("script");
			for(var i=0;i<scriptTags.length;i++) {
				if(scriptTags[i].src && scriptTags[i].src.match(/librarymanager\.js(\?.*)?$/)) {
					this.path = scriptTags[i].src.replace(/librarymanager\.js(\?.*)?$/,'');
					break;
				}
			}
		}
	},
	
	
	/**
	 * Calculates state of site, are we in cms or not?
	 *
	 * @return void  
	 */
	 calculateState: function() {
		
		// condition : is object var already set?
		if (this.iscms === null) {
			// condition : is _cms in url?
			if(location.href.match(/cms/)) {
				this.iscms = true;
			} else {
				this.iscms = false;
			}
		}
	},

	
	/**
	 * Calculates the current page class and id 
	 *
	 * @return void  
	 */
	calculatePageDetails: function() {
		this.pageId = document.getElementsByTagName("body")[0].id; 
		this.pageClass = document.getElementsByTagName("body")[0].className;
	},	
	
	
	/**
	 * Includes a js file
	 * 
	 * @param string libraryfile The path from the js library root to the file
	 *
	 * @return void  
	 */
	require: function(libraryfile) {
		document.write('<script type="text/javascript" src="'+ this.path + libraryfile +'"></script>');
	},
	
	
	/**
	 * function to add event-listeners (cross-browser compatible)
	 * By John Resig - http://ejohn.org/projects/flexible-javascript-events/
	 * 
	 * @param obj object the html element object to attach the event to
	 * @param type string the event type (e.g. 'load', 'keypress', 'click')
	 * @param fn string the name of the function to call  		
	 *
	 * @return void  
	 */
	addEvent: function (obj, type, fn) {
		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]);
		} else if (obj.addEventListener) {
	     	obj.addEventListener(type, fn, false);
		} else {
			var oldfn = obj['on'+type];
			if (typeof obj['on'+type] != 'function') {
			     obj['on'+type] = fn;
			} else {
			     obj['on'+type] = function() {
			       oldfn();
			       fn();
			     };
			}
		}
	 },


	/**
	 * function to remove event-listeners (cross-browser compatible)
	 * also by John Resig
	 * 
	 * @param obj object the html element object to remove the event from
	 * @param type string the event type
	 * @param fn string the name of the function name to remove   		
	 *
	 * @return void  
	 */
	 removeEvent: function(obj, type, fn) {
	   	if (obj.detachEvent) {
	    	obj.detachEvent('on'+type, obj[type+fn]);
	    	obj[type+fn] = null;
	   	} else {
	    	obj.removeEventListener(type, fn, false);
		}
	 },
	
	
	/**
	 * Ensures functions are only run once the core library is loaded
	 * Detects when the DOM tree has loaded, then triggers all onload events
	 * 
	 * @param function func The function to execute
	 *
	 * @return void  
	 */
	addLoadEvent: function (func) {
		
		// add the latest event to the list of DOMload events - Win IE5 doesn't support Array.push so...
		this.loadEvents[this.loadEvents.length] = func;
		
		// test whether the DOM load event listener has been added yet - only needs adding the first time
		if (this.loadEvents.length == 1) {

			// detect whether one form of dom load is supported
			var domLoadSupported = false;

			// firefox & Opera 9 support natively DOM load
			if (document.addEventListener) {
				document.addEventListener("DOMContentLoaded", this.onDomLoaded, null);
				domLoadSupported = true;
			}
		
			// safari & konqueror have an alternative DOM load detector 
			if (/KHTML|WebKit/i.test(navigator.userAgent)) { 
				var _timer = setInterval(function() {
					if (/loaded|complete/.test(document.readyState)) {
						clearInterval(_timer);
						delete _timer;
						LibraryManager.onDomLoaded();
					}
				}, 10);
				domLoadSupported = true;
			}
		
			// Win IE uses a script with a 'defer' attribute for DOM load detection  
			/*@cc_on @*/
			/*@if (@_win32)
			var proto = "javascript:void(0)";
			if (location.protocol == "https:") proto = "src=//0";
			document.write("<scr"+"ipt id=__ie_onload defer src=" + proto + "><\/scr"+"ipt>");
			var script = document.getElementById("__ie_onload");
			script.onreadystatechange = function() {
			    if (this.readyState == "complete") {
			        LibraryManager.onDomLoaded();
			    }
			};
			domLoadSupported = true;
			/*@end @*/

			// legacy browsers - load events added when everything has finished loading
			if (!domLoadSupported) {
				this.addEvent(window, 'load', this.onDomLoaded);
			}
		}
	},
	
	
	/**
	 * Private function called when the DOM tree has loaded, 
	 * to cycle through and execute all on load events
	 * 
	 * @return void  
	 */
	onDomLoaded: function () {
		if (arguments.callee.done) return;
		arguments.callee.done = true;
		for (var i=0; i<LibraryManager.loadEvents.length; i++) {
		 	LibraryManager.loadEvents[i]();
		}
	}
}


/*
 * function to add a background grid/image to an html element on key presses
 *
 * @author Pete Goodman
 * @author Richard Hallows - portable
 */

var Grid = {

	//set initial variable for whether the grid is currently shown
	gridVisible : false,

	//set variable to show whether the grid-containing element has had to be created
	gridElementCreated : false,

	//variables for the grid element
	gridHolder : {},	
	gridSrc : "",
	gridPos : "",
	gridRepeat : "",
	
	
	/*
	 * function to set the initial grid values
	 * @param string gridElement the id or html tag to place the grid behind
	 * @param string gridSrc the image source for the grid - relative to the html page
	 * @param string gridPos the CSS positioning statement (eg 'left top', '50% 50%')
	 * @param string gridRepeat the CSS repeat value (eg 'no-repeat','repeat-x','repeat-y')
	 */
	initialize: function(gridElement, gridSrc, gridPos, gridRepeat) { 

		//the html element holder, once we've found it
		this.gridHolder = this.getGridElement(gridElement);
	
		// if the function above doesn't find a grid element, then create a new element to hold it
		if (!this.gridHolder || this.gridHolder.length==0 ) {
			
			//get the body element
			var body = document.getElementsByTagName("body")[0];


			//create the new html element
			var overlay = document.createElement('div');
			overlay.id = gridElement;
			overlay.style.width = "100%";
			overlay.style.position = "absolute";
			overlay.style.top = "2px";
			overlay.style.left = "33px";
			overlay.style.zindex = "9999";
			overlay.style.display = "none";
			

			//for Win IE: set the height as the document height
			if (window.attachEvent) {
				overlay.style.height = document.body.offsetHeight;

			//for all other browsers, set element height at 100%
			} else { 
				overlay.style.height = "100%";
			}


			//add the new html element to the document
			body.appendChild(overlay);
			
			//set the element holder to the new element
			this.gridHolder = overlay;

			//set the variable telling the key checker that it applying to a new element
			this.gridElementCreated = true;
		};

		//if the function has found a grid element, set the root object variables
		this.gridSrc = gridSrc;
		this.gridPos = gridPos;
		this.gridRepeat = gridRepeat;
		
		//add the events
		LibraryManager.addEvent(document, 'keydown', this.keyCheck, false);
	
	},


	/*
	 * find the element that will contain the grid, by testing if its an id or tag
	 * @param string gridElement the id or html tag to place the grid behind
	 * @return object the html element in question
	 */
	getGridElement: function(gridElement) {
		var el;
		
		//test if its an id
		el	= noconflict$(gridElement);

		//if not, get the tag with the name
		if (!el) {
			el = document.getElementsByTagName(gridElement)[0];
		}
		return el;
	}, 


	/*
	 * function to detect when the required keys are pressed, and act accordingly
	 * @param event e the current window event
	 */
	keyCheck: function(e) { 
		
		//get the ids of which keys have been pressed
		var keyID = (window.event) ? event.keyCode : e.keyCode;
		var ctrlKey = (window.event) ? event.ctrlKey : e.ctrlKey;
		
		//alert(e.keyCode + ", " + e.ctrlKey);

		//test to see if its the selected keys
		//59 = win IE
		//186 = win FF & win Opera & mac Safari
		//90 = mac Opera
		if((keyID == 59 || keyID == 186 || keyID == 90)&&(ctrlKey == true))  { 

			
			//if the bg is currently shown, remove it
			if (Grid.gridVisible === true) {

				Grid.gridHolder.style.backgroundImage = "none";
	
				//if the grid-containing element was created, set display to none so you can select items below
				if (Grid.gridElementCreated === true) {
					Grid.gridHolder.style.display = "none";
				}

				Grid.gridVisible = false;

			//else, the grid is hidden, so show it
			} else { 

				Grid.gridHolder.style.backgroundImage = "url('" + Grid.gridSrc + "')";
				Grid.gridHolder.style.backgroundPosition = Grid.gridPos;
				Grid.gridHolder.style.backgroundRepeat = Grid.gridRepeat;

				//if the grid-containing element was created, display the image
				if (Grid.gridElementCreated === true) {
					Grid.gridHolder.style.display = "block";
				}

				//set variable to show the grid is now shown
				Grid.gridVisible = true;			
			}
		}
	}
}


/*
 * $ function - noconflict
 * extracted from prototype library - http://prototype.conio.net/
 * replaces and extends document.getElementById
 */
function noconflict$() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')  
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}


// start the js library manager
LibraryManager.initialise();

/*
 * add on DOM load events
 */
LibraryManager.addLoadEvent( 
	function() {
		var pageid = document.getElementsByTagName("body")[0].id; 
		//console.debug("../resources/" + pageid + ".jpg");
		Grid.initialize("template", "../resources/mockups/" + pageid + ".jpg", "center top", "no-repeat");
	}
);
