/*
 * 
 * ADOBE CONFIDENTIAL
 * ___________________
 * 
 * Copyright 2010 Adobe Systems Incorporated
 * All Rights Reserved.
 * 
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

if (typeof Muse == "undefined") window.Muse = {};

/** Assert *************************************************************/

Muse.Assert = {};

Muse.Assert.fail = function(s)
{
	// Note: This will eventually get wired to a runtime error reporting scheme that
	// works well with the snapshotting work..
	alert("MuseJSAssert: " + s);
}

/** Array **************************************************************/

if(!Array.indexOf)
{
    Array.prototype.indexOf = function(obj)
    {
        for(var i=0; i<this.length; ++i)
        {
            if(this[i]==obj)
                return i;	            
	    }
	    return -1;	    
	}
}

/** Plugin *************************************************************/

Muse.Plugins = {};

/** Utils **************************************************************/

Muse.Utils = {};

// Load listener ----------------------------------------------------

Muse.Utils.addLoadListener = function(llfn)
{
	if (false)
	{
		// Calling each function at the end before a DOM is ready/a page is loaded is not guaranteed to work
		// Some browsers with WebKit requires DOM/page loaded for proper JS execution
		if (!Muse.Utils.loadListeners) Muse.Utils.loadListeners = [];
		Muse.Utils.loadListeners.push(llfn);
	}
	else
	{
		// Calling each function at page load is late and see more transitional progress by JS
		// Change to do it sooner at document ready
		// Spry.Utils.addLoadListener(llfn);
		jQuery(document).ready(llfn);
	}
}

Muse.Utils.runLoadListeners = function()
{
	if (!Muse.Utils.loadListeners) return;
	
	for(var i = 0; i < Muse.Utils.loadListeners.length; i++)
	{
		try
		{
			Muse.Utils.loadListeners[i]();
		}
		catch(e) { Muse.Assert.fail("LoadListener failed: " + e); }
	}
}

Muse.Utils.selectorFns = [];

Muse.Utils.addSelectorFn = function(sel, fn)
{
	Muse.Utils.selectorFns.push({selector:sel, selFn:fn});
}

Muse.Utils.addLoadListener(
	function()
	{ 
		for (var i=0; i < Muse.Utils.selectorFns.length; i++)
		{
			try { 
				Spry.$$(Muse.Utils.selectorFns[i].selector).forEach(Muse.Utils.selectorFns[i].selFn); 
			} 
			catch(e) { Muse.Assert.fail("Error calling selector function:" + e); }
		}
	}
);

// Touch Detection --------------------------------------------------

Muse.Utils.isTouchDevice = function()
{
	try 
	{
		document.createEvent("TouchEvent");
		return true;
	} 
	catch (e)
	{
		return false;
	}	
}

// Element manipulation ---------------------------------------------

// Replace 'elem' with 'wrapper', add 'elem' to 'wrapper' childnodes.
Muse.Utils.wrapElement = function(elem, wrapper)
{
	elem.parentNode.replaceChild(wrapper, elem);
	wrapper.appendChild(elem);
}

// Find the first child (if any) which matches the 'matchFind' criteria.
Muse.Utils.firstChild = function(elem, matchFind)
{
	for (var iChild = 0; iChild < elem.childNodes.length; iChild++)
	{
		var ch = elem.childNodes[iChild];
		if (ch.nodeType != 1) continue;

		if (!matchFind || matchFind.matches(ch)) return ch;
	}
	
	return null;
}

// Find the first descendant that matches 'matchFind.' Do not recurse into
// any elements which match 'matchBlock'
Muse.Utils.firstDescendant = function(elem, matchFind, matchBlock)
{
	for (var iChild = 0; iChild < elem.childNodes.length; iChild++)
	{
		var ch = elem.childNodes[iChild];
		if (ch.nodeType != 1) continue;

		if (!matchFind || matchFind.matches(ch)) return ch;
		if (matchBlock && matchBlock.matches(ch)) continue;
		
		var desc = Muse.Utils.firstDescendant(ch, matchFind, matchBlock);
		if (desc) return desc;
	}
	
	return null;
}

// Returns an array of all descendants which match 'matchFind'. 
// Does not recurse into any elements which match 'matchBlock'.
// Returned array supports forEach()
Muse.Utils.descendants = function(elem, matchFind, matchBlock, addTo)
{
	if (!addTo) 
	{
		addTo = [];
		addTo.forEach = function(f) { for(var i = 0; i < this.length; i++) if (f(this[i])) break; };
		addTo.forEachTry = function(f) { for(var i = 0; i < this.length; i++) { try { if (f(this[i])) break; } catch(e) {} }}
	}

	for (var iChild = 0; iChild < elem.childNodes.length; iChild++)
	{
		var ch = elem.childNodes[iChild];
		if (ch.nodeType != 1) continue;

		if (!matchFind || matchFind.matches(ch)) addTo.push(ch);
		if (!matchBlock || !matchBlock.matches(ch)) Muse.Utils.descendants(ch, matchFind, matchBlock, addTo);
	}
	
	return addTo;
}

Muse.Utils.children = function(elem, matchFind)
{
	return Muse.Utils.descendants(elem, matchFind, Muse.Utils.Match.always);
}

Muse.Utils.Match = {}

// Helper match class

Muse.Utils.Match.ByClass = function(cl) { this.cl = cl; }
Muse.Utils.Match.ByClass.prototype.matches = function(e) { return Spry.Utils.hasClassName(e, this.cl); }

// Helper match class
Muse.Utils.Match.ByNodeName = function(nm) { this.nm = nm.toLowerCase(); }
Muse.Utils.Match.ByNodeName.prototype.matches = function(e) { return this.nm == e.nodeName.toLowerCase(); }

// Helper match class
Muse.Utils.Match.ByFixed = function(m) { this.matchResult = m; }
Muse.Utils.Match.ByFixed.prototype.matches = function(e) { return this.matchResult; }

// Helper constructors -- normally these are the ones used as args to children(), descendants()
Muse.Utils.Match.byClass = function(cl) { return new Muse.Utils.Match.ByClass(cl); }
Muse.Utils.Match.byNodeName = function(nm) { return new Muse.Utils.Match.ByNodeName(nm); }
Muse.Utils.Match.byFixed = function(m) { return new Muse.Utils.Match.ByFixed(m); }

// 'Constant' matchers
Muse.Utils.Match.always = Muse.Utils.Match.byFixed(true);
Muse.Utils.Match.never = Muse.Utils.Match.byFixed(false);

Muse.Utils.moveChildren = function(elemFrom, elemTo)
{
	while(elemFrom.childNodes.length > 0) elemTo.appendChild(elemFrom.childNodes[0]);
}

Muse.Utils.copyChildren = function(elemFrom, elemTo)
{
	for(var i = 0; i < elemFrom.childNodes.length; i++) elemTo.appendChild(elemFrom.childNodes[i].cloneNode(true));
}

Muse.Utils.copyChildrenBefore = function(elemFrom, elemBefore)
{
	for(var i = 0; i < elemFrom.childNodes.length; i++) elemBefore.parentNode.insertBefore(elemFrom.childNodes[i].cloneNode(true), elemBefore);
}

// CSS --------------------------------------------------------------

Muse.Utils.pixelRound = function(n)
{
	return Math.floor((n * 100.0 + 0.5) / 100.0);
}

Muse.Utils.getCurrentHTMLFileName = function(includeExtension)
{
	var href = document.location.href;
	var fileName;
	if (href.charAt(href.length - 1) == '/')
		fileName = "index";
	else
		fileName = href.substring(href.lastIndexOf("/") + 1, href.lastIndexOf("."));
		
	if (includeExtension)
		fileName += ".html";
		
	return fileName;
}

Muse.Utils.getPageStyleSheet = function()
{
	var cssFileName = "/" + Muse.Utils.getCurrentHTMLFileName(false).toLowerCase() + ".css";
	
	for(var i = 0; i < document.styleSheets.length; ++i) 
	{
		var sheet = document.styleSheets[i]
		if(sheet.href && sheet.href.toLowerCase().indexOf(cssFileName) != -1) 
			return sheet;
	}
}

Muse.Utils.getStyleSheetRuleById = function(sheet, id)
{
	var isIE = false;
	var idStr = "#" + id.toLowerCase();
	var rules = sheet.cssRules;
	if (!rules)
	{
		isIE = true; 
		rules = sheet.rules;
	}

	if (rules)
	{
		for(var i = 0; i < rules.length; ++i) 
		{
			var rule = rules[i];
			if (isIE)
			{
				if (rule.selectorText.toLowerCase() == idStr)
					return rule;
			}
			else
			{
				var selectors = rule.selectorText.toLowerCase().split(", ");
				if (selectors.indexOf(idStr) != -1)
					return rule;
			}
		}
	}
	return null;
}

Muse.Utils.setRuleProperty = function(rule, prop, value)
{
	if (rule.style.setProperty)
		rule.style.setProperty(prop, value, "");
	else
		rule.style.setAttribute(prop, value, 0);
}

Muse.Utils.removeRuleProperty = function(rule, prop)
{
	if (rule.style.removeProperty)
		rule.style.removeProperty(prop);
	else
		rule.style.removeAttribute(prop, 0);
}

// Returns newID of a newly clone StyleSheet rule
Muse.Utils.cloneStyleSheetRule = function(id)
{
	if( typeof Muse.Utils.cloneStyleSheetRule.newNumber == 'undefined' ) {
        Muse.Utils.cloneStyleSheetRule.newNumber = 1;
    }
	
	var sheet = Muse.Utils.getPageStyleSheet(id);
	var rule = Muse.Utils.getStyleSheetRuleById(sheet, id);
	var newID = "c" + Muse.Utils.cloneStyleSheetRule.newNumber++;
	var newSelector = "#" + newID;
	
	if (sheet.insertRule)
		sheet.insertRule(rule.cssText.replace("#" + id, newSelector), sheet.cssRules.length);
	else
		sheet.addRule(newSelector, rule.style.cssText);	

	return newID;
}

Muse.Utils.toCamelCase = function(s) 
{
	for(var exp = Muse.Utils.toCamelCase.exp; 
		exp.test(s); s = s.replace(exp, RegExp.$1.toUpperCase()) );
	return s;
}
Muse.Utils.toCamelCase.exp = /-([a-z])/;

// style parameter should conform to CSS property name, for example, width, padding-left, margin-right
Muse.Utils.getStyleValue = function(elem, style) 
{
	var value = elem.style[Muse.Utils.toCamelCase(style)];
	if(!value)
		if(document.defaultView)
			value = document.defaultView.getComputedStyle(elem, "").getPropertyValue(style);
		else if(elem.currentStyle)
			value = elem.currentStyle[Muse.Utils.toCamelCase(style)];
	
	if (value.match(/(\d+)px/))
		value = parseInt(value.substring(0, value.length - 2));
	return value;
}

// Hyperlink --------------------------------------------------------

var mousedownStack = new Array;

Muse.Utils.redirectHyperlink = function(elem)
{
	mousedownStack = new Array;
	
	var href = elem.href;
	var targetClass = jQuery(elem).attr("class").match(/target_(\w+)/);
	
	if (!targetClass)
	{
		var lastFSlashIndex = href.lastIndexOf("/");
		var lastPoundIndex = href.lastIndexOf("#");
		if (lastPoundIndex > lastFSlashIndex)
		{
			var currentHTML = Muse.Utils.getCurrentHTMLFileName(true); 
			if (href.substring(lastFSlashIndex + 1, lastPoundIndex) == currentHTML)
			{
				var destination = href.substring(lastPoundIndex);
				
				var animationClass = jQuery(elem).attr("class").match(/anim_(\w+)/);
				if (animationClass)
				{
					var speed = 1000;
					var animation = animationClass[1];
					var distanceTop = jQuery(destination).offset().top;
					var distanceLeft = jQuery(destination).offset().left;
					
					jQuery("html,body").animate({ scrollTop: distanceTop, scrollLeft: distanceLeft }, speed, animation);
					return;
				}
					
				// Default
				window.location.hash = destination;
				return;
			}
		}
	}
	
	var target = targetClass? targetClass[0].substring("target".length) : "_self";
	window.open(href, target);
} 

Muse.Utils.addHyperlinkAnchor = function(elem)
{
	Spry.Utils.addEventListener(elem, "mousedown", function() {
	   			mousedownStack.push(elem);
	   			return false;
	   		}, false);	
				
	Spry.Utils.addEventListener(elem, "mouseup", function() {
				if (mousedownStack.indexOf(elem) != -1)
					Muse.Utils.redirectHyperlink(elem);
	   			return false;
	   		}, false);
	   		
	Spry.Utils.addEventListener(elem, "click", function() {
	   			return false;
	   		}, false);
}

Muse.Utils.addHyperlinkBlock = function(elem)
{
	Spry.Utils.addEventListener(elem.parentNode, "mousedown", function() {
					mousedownStack.push(elem.parentNode);
	    			return true;
	    		}, false);	
				
	Spry.Utils.addEventListener(elem.parentNode, "mouseup", function() {
	    			var upElem = elem.parentNode;
					if (mousedownStack.indexOf(upElem) != -1)
						Muse.Utils.redirectHyperlink(elem);
					return true;
	    		}, false);
}

// Image -------------------------------------------------------------

Muse.Utils.getNaturalWidth = function(img) 
{
	var naturalWidth  = -1;
	if(img.naturalWidth != null)
		naturalWidth = img.naturalWidth;
	else if(img.runtimeStyle) 
	{
		img.runtimeStyle.width= 'auto';
		img.runtimeStyle.height= 'auto';
		img.runtimeStyle.borderWidth= '0';
		img.runtimeStyle.padding= '0';
		naturalWidth =  img.offsetWidth;
		img.runtimeStyle.width= '';
		img.runtimeStyle.height= '';
		img.runtimeStyle.borderWidth= '';
		img.runtimeStyle.padding= '';
	} 
	else 
	{
		var tempImg = img.cloneNode(true);
		tempImg.className = '';
		tempImg.style.width = 'auto !important';
		tempImg.style.height = 'auto !important';
		tempImg.style.borderWidth= '0 !important';
		tempImg.style.padding= '0 !important';
		naturalWidth =  tempImg.width;
	}
	return(naturalWidth);
}

Muse.Utils.getNaturalHeight = function(img) 
{
	var naturalHeight  = -1;
	if(img.naturalHeight != null) 
		naturalHeight = img.naturalHeight;
	else if(img.runtimeStyle)
	{
		img.runtimeStyle.width= 'auto';
		img.runtimeStyle.height= 'auto';
		img.runtimeStyle.borderWidth= '0';
		img.runtimeStyle.padding= '0';
		naturalHeight = img.offsetHeight;
		img.runtimeStyle.width= '';
		img.runtimeStyle.height= '';
		img.runtimeStyle.borderWidth= '';
		img.runtimeStyle.padding= '';
	}
	else 
	{
		var tempImg = img.cloneNode(true);
		tempImg.className = '';
		tempImg.style.width = 'auto !important';
		tempImg.style.height = 'auto !important';
		tempImg.style.borderWidth= '0 !important';
		tempImg.style.padding= '0 !important';
		naturalHeight =  tempImg.height;
	}
	return(naturalHeight);
}
