/**
 * This script addresses a specific issue: should alpha transparent images be
 * used to overlay some text, user cannot click trough transparent areas.
 * 
 * The script works by substituting narrower blocks to the transparent image 
 * recipient, and sharing the transparent image among these blocks.
 * 
 * Note:
 * 	 The script is intended to be includded in the header of the page, 
 *   prefferably at the end of the 'link' style inclusions list.
 * 
 * Claudius Tiberiu Iacob <claudius.iacob@gmail.com>
 * 2008/09/08
 * GNU License v.2
 */

// Internet Explorer 6 runs a legacy layout, so no fix required for it. 
var isMSIE6OrLess = false /*@cc_on || @_jscript_version < 5.7 @*/;
if (!isMSIE6OrLess) {
	
	// Everything should be customized in here:
	// [params]-----------------------------------------------------------------
	var elementsList = {
		'footerImg' : {
			// The element id. Note that the slice process will remove this
			// element. Do not confide it page content, merely give it a 
			// graphicall background.
			'id' : 'footer',
			
			// One of the 'TL', 'TR', 'BL', 'BR'.
			'anchor' : 'BR',
			
			// Format:
			// [<VERTICAL>, <HORIZONTAL>, <HEIGHT>]
			//
			// Slices are layed down vertically, one next to each other,
			// from left to right when anchor is 'TL' or 'BL', and from
			// right to left when anchor is 'TR' or 'BR'.
			// 
			// Use '-1' for <HEIGHT> if you want the slice to span to the
			// oposite element border.
			// TOP LEFT COORDINATES:
//			'coords' : [
//				[140,0,-1],
//				[122,30,-1],
//				[110,50,-1], 
//				[100,80,-1],
//				[90,100,-1],
//				[80,120,-1],
//				[95,155,-1],
//				[85,180,-1],
//				[65,200,-1],
//				[0,215,-1]				
//			]
//			// TOP RIGHT COORDINATES:
//			'coords' : [
//				[0,0,-1],
//				[65,31,-1],
//				[85,46,-1],
//				[95,66,-1],
//				[80,91,-1],
//				[90,126,-1],
//				[100,146,-1],
//				[110,166,-1],
//				[122,196,-1],
//				[140,216,-1]
//			]
			// BOTTOM RIGHT COORDINATES:
			'coords' : [
				[0,0,176],	
				[0,31,111],	
				[0,46,91],	
				[0,66,81],	
				[0,91,96],	
				[0,126,86],	
				[0,146,76],	
				[0,166,66],	
				[0,196,54],	
				[0,216,36]	
			]
		}
	}
	// [/params]----------------------------------------------------------------
	
	/**
	 * Gets initial list of elements, as provided by the user.
	 * @return {Array}
	 */
	function grabTargetElList () {
		var ret = [];
		for (var uid in elementsList) {
			ret.push (uid);
		}
		return ret;
	}
	
	/**
	 * Cross-browser routine that retrieves a certain computed style value
	 * from a given element.
	 * @param {Object} oElm
	 * 		The element to get computed style from.
	 * @param {String} strCssRule
	 * 		The CSS rule to look for.
	 * @return {String}
	 * 		The CSS rule value.
	 * @credits: "http://www.robertnyman.com/2006/04/24/
	 * 		get-the-rendered-style-of-an-element/"
	 */
	function getStyle (oElm, strCssRule) {
		var strValue = "";
		if (document.defaultView && document.defaultView.getComputedStyle) {
			strValue = document.defaultView.getComputedStyle (oElm, "").	
				getPropertyValue (strCssRule);
		} else if (oElm.currentStyle) {
			strCssRule = strCssRule.replace (/\-(\w)/g, 
				function (strMatch, p1) {
					return p1.toUpperCase();
				}
			);
			strValue = oElm.currentStyle[strCssRule];
		}
		return strValue;
	}
	
	// Make sure we are notified after the page document has loaded -- no search
	// for appropriate CSS declaration is done past tis moment.
	var isDocumentLoaded = false;
	// For some reason, Microsoft thought that IE7 isn't a good place to 
	// implement the standard DOM Event model functions, like 
	// 'addEventListener()'...
	// 
	// I HATE THEM. I REALLY DO [:angry:]
	if (typeof window.addEventListener == 'function') {
		window.addEventListener ('load', function() {
				isDocumentLoaded = true;
				window.removeEventListener ('load', arguments.callee, false);
			},
			false 
		);
	} else {
		window.attachEvent ('onload', function() {
				isDocumentLoaded = true;
				window.detachEvent ('onload', arguments.callee);
			}
		)
	}
	
	// Flag to set once DOM check completed. This dismisses pending subsequent
	// calls to 'checkDomReady()'.
	var domCheckCompleted = false;
	
	/**
	 * Reiterativelly checks for the presence of the BODY element within the
	 * DOM; this gives us the right to manipulate elements within.
	 */
	function checkDomReady () {
		if (domCheckCompleted) {
			return;
		}
		var haveBodyLoaded = document.getElementsByTagName('body')[0];
		if (!haveBodyLoaded) {
			window.setTimeout (checkDomReady, 1000);
			return;
		}
		domCheckCompleted = true;
		checkCssReady ();	
	}
	
	// Flag to set once CSS check completed. This dismisses pending subsequent
	// calls to 'checkCssReady()'. 
	var haveCssLoaded = false;
	
	// The list of elements to alter, as we got it from the user.
	var elUidsToCheck = grabTargetElList ();

	/**
	 * Checks whether several CSS properties are declared on every element in 
	 * our list.
	 * 
	 * This check is a recurring process, since most modern browsers load 
	 * CSS files asynchronously; we keep checking for CSS properties until we
	 * find them, or until our document has loaded -- case in which we drop the 
	 * element off the list.
	 */
	function checkCssReady () {
		if (haveCssLoaded) { return; } // ...make sure this only runs once.
		for (var i=0; i<elUidsToCheck.length; i++ ) {
			var elUid = elUidsToCheck [i];
			if (elUid === '') { continue; }
			var isMissing = checkIfMissing (elUid);
			if (isMissing) {
				elUidsToCheck [i] = '';
				delete elementsList [elUid];
			}
			var isCssOk = checkCssFor (elUid);
			if (isCssOk) {
				elUidsToCheck [i] = '';
			}
		}
		if (!isDocumentLoaded) {
			if (elUidsToCheck.join ('') !== '') {
				window.setTimeout(checkCssReady, 1000);
				return;
			}
		}
		sliceElements ();
		haveCssLoaded = true;
	}
	
	/**
	 * Tests whether given UID points to a non-existing HTML Element.
	 * @param {String} uid
	 * 		The unique id to check.
	 * @return {Boolean}
	 * 		True if the element doesn't exist (anymore).
	 */
	function checkIfMissing (uid) {
		var elId = elementsList [uid] ['id'];
		var el = document.getElementById(elId);
		return (el === null);	
	}
	
	/**
	 * Tests whether given UID points to an element whose CSS declaration are
	 * legal given our set of regulations:
	 * - an 'background-image' must be set;
	 * - position must be set to one of 'fixed', 'absolute', or 'relative';
	 * - element's width and height must be defined, in pixels;
	 * - element must be anchored at one, and only one, of its four corners,
	 *   by a set of appropriate CSS declarations, such as: 'top/left', or
	 * 	 'top/right', or 'bottom/left', or 'bottom/right'. Moreover, this must
	 *   respect the element's declared "anchor" property.
	 */
	function checkCssFor (uid) {
		var elId = elementsList [uid] ['id'];
		var el = document.getElementById(elId);
        if (!el) { 
            return false;
        }
		var elBgImg = getStyle (el, 'background-image');
		var hasBg = (elBgImg !== '' && elBgImg !== 'none');
		var elPos = getStyle (el, 'position');
		var hasPos = (elPos !== '' && (elPos === 'fixed' || 
			elPos === 'absolute' || elPos === 'relative'));
		var elW = getStyle (el, 'width');
		var hasW = isPixelValue(elW);
		var elH = getStyle (el, 'height');
		var hasH = isPixelValue(elH);
		if (hasBg && hasPos && hasW && hasH) {
			var elLeft = getStyle (el, 'left');
			var hasLeft = isPixelValue (elLeft);
			var elTop = getStyle (el, 'top');
			var hasTop = isPixelValue (elTop);
			var elRight = getStyle (el, 'right');
			var hasRight = isPixelValue (elRight);
			var elBottom = getStyle (el, 'bottom');
			var hasBottom = isPixelValue (elBottom);
			var anchor =  elementsList [uid]['anchor'];
			switch (anchor) {
				case 'TL':
					return hasLeft && hasTop;
				case 'TR':
					return hasRight && hasTop;
				case 'BL':
					return hasLeft && hasBottom;
				case 'BR':
					return hasRight && hasBottom;
			} 	
		}
		return false;
	}
	
	/**
	 * Checks a string agains the CSS pixel value pattern.
	 * @param {String} value
	 * 		The string to check.
	 * @return {boolean}
	 * 		True if the string looks like a CSS pixel value pattern.
	 */
	function isPixelValue (value) {
		return (value !== '' && value !== 'auto' && /\d+px/.test(value));
	}
	
	/**
	 * Convenience way to get a slice dataset.
	 * @param {String} uid
	 * 		The element's UID.
	 * @param {Number} index 
	 * 		The slice numeric index within the 'coords' element field.
	 * @return {Object}
	 * 		An object, such as: 
	 * 		{
	 * 			'vert':   0,
	 * 			'horz':   0, 
	 * 			'height': 0
	 *		}
	 */
	function getSliceData (uid, index) {
		var set = elementsList [uid]['coords'][index];
		if (set) {
			if (typeof set[0] != 'number' ||
				typeof set[1] != 'number' ||
				typeof set[2] != 'number') {
				var err = 'Please specify all of your coordinates as ' +
						'numbers.\n' +
						'Check \'' + uid + '.coords[' + index + ']\'';
				throw (new Error (err));
			} 
			return {
				'vert':   set [0],
				'horz':   set [1], 
				'height': set [2]
			}
		}
		return null;
	}

	/**
	 * Slices all the elements left in the list, as directed by the coordinates
	 * provided by user, and displays appropriate portions of the background
	 * image on each slice.
	 * 
	 * After slicing is completed, the original element is *REMOVED* from the 
	 * DOM.
	 */
	function sliceElements () {
        var el = null;
		for (var uid in elementsList) {
			if (!elementsList[uid]['coords'] || 
				elementsList[uid]['coords'].length == 0) { 
				return; 
			}
			if ((elUidsToCheck.join (',')).indexOf (uid) != -1) {
				continue;
			}
			var el = document.getElementById(elementsList[uid]['id']);
            if (!el) { 
                return; 
            }
			var pos = getStyle (el, 'position');
			var zIndex = parseInt (getStyle (el, 'z-index')) || '';
			var w = parseInt (getStyle (el, 'width'));
			var h = parseInt (getStyle (el, 'height'));
			var bgUrl = getStyle (el, 'background-image');
			var left = parseInt (getStyle (el, 'left'));
			if (isNaN (left)) { left = 'auto'; }
			var top = parseInt (getStyle (el, 'top'));
			if (isNaN (top)) { top = 'auto'; }
			var right = parseInt (getStyle (el, 'right'));
			if (isNaN (right)) { right = 'auto'; }
			var bottom = parseInt (getStyle (el, 'bottom'));
			if (isNaN (bottom)) { bottom = 'auto'; }
			var parseSliceCoords = function (uid, sliceData, nextSliceData) {
				var a = elementsList[uid]['anchor'];
				var hParam, vParam, anchorPoints;
				switch (a) {
					case 'TL':
						vParam = top;
						hParam = left;
						anchorPoints = {'vert' : 'top', 'horz' : 'left'};
						break;
					case 'TR':
						vParam = top;
						hParam = right;
						anchorPoints = {'vert' : 'top', 'horz' : 'right'};
						break;
					case 'BL':
						vParam = bottom;
						hParam = left;
						anchorPoints = {'vert' : 'bottom', 'horz' : 'left'};
						break;
					case 'BR':
						vParam = bottom;
						hParam = right;
						anchorPoints = {'vert' : 'bottom', 'horz' : 'right'};
				}
				var sliceBgVert = sliceData.vert;
				var sliceBgHorz = sliceData.horz;
				var sliceVert = sliceData.vert + vParam;
				var sliceHorz = sliceData.horz + hParam;
				var sliceWidth = nextSliceData? nextSliceData.horz - 
					sliceData.horz : w - sliceData.horz;
				var sliceHeight = (sliceData.height == -1)? h - sliceData.vert :
					sliceData.height;
				return {
					'sBgVert' : sliceBgVert,
					'sBgHorz' : sliceBgHorz,
					'sVert'   : sliceVert,
					'sHorz'   : sliceHorz,
					'sWidth'  : sliceWidth,
					'sHeight' : sliceHeight,
					'aPoints' : anchorPoints
				}
			}
			for (var i=0; i<elementsList [uid]['coords'].length; i++) {
				var sliceData = getSliceData (uid, i);
				if (!sliceData) {
					var err = 'Slice data at index ' +i+ ' wasn\'t found.\n' +
							'Please check the \'coords\' property of the' +
							'\'' +uid+ '\' object that you defined.';
					throw (new Error (err));
					return; 
				}
				var nextSliceData = getSliceData (uid, i+1);
				var sCoords = parseSliceCoords(uid, sliceData, nextSliceData);
				var bgPos = '';
				var a = elementsList[uid]['anchor'];
				if (a == 'TL' || a == 'BL') {
					bgPos += '-' + (sCoords['sBgHorz']) + 'px';
				}
				if (a == 'TR' || a == 'BR') {
					bgPos += '-' + (w - sCoords['sWidth'] - 
						sCoords['sBgHorz']) + 'px';
				}
				bgPos += ' ';
				if (a == 'TL' || a == 'TR') {
					bgPos += '-' + (sCoords['sBgVert']) + 'px';
				}
				if (a == 'BL' || a == 'BR') {
					bgPos += '-' + (h - sCoords['sHeight'] - 
						sCoords['sBgVert']) + 'px';
				}
				var slice = document.createElement ('div');
				slice.className = 'slice';
				slice.style.position = pos;
				slice.style.zIndex = zIndex;
				slice.style.backgroundImage = bgUrl;
				slice.style.backgroundRepeat = 'no-repeat';
				slice.style[sCoords['aPoints']['vert']] = sCoords['sVert']+'px';
				slice.style[sCoords['aPoints']['horz']] = sCoords['sHorz']+'px';
				slice.style.width = sCoords['sWidth']+'px';
				slice.style.height = sCoords['sHeight']+'px';
				slice.style.backgroundPosition = bgPos;
				el.parentNode.appendChild (slice);
			}
		}
        if (!el) { 
            return; 
        }
		var pNode = el.parentNode;
		pNode.removeChild (el);
	}
	// RUN:
	checkDomReady ();
}



