/*
 * Global Variables and utility functions
 */

// main namespace
if (typeof(mobile) == "undefined") var mobile = {};

// store reference to body element, will be set on dom:loaded (see below).
var documentBody;

// This is the main JS initialization listener. Listens to DomReady and fires
// "mobile:*" events on the document element.
// Listen for these events in other scripts to initialize.
// Also sets some gloabl utility variables.
mobile._initialize = function() {
	
	document.fire("mobile:init");

	// global var for document.body, performance optimization for css selects
	documentBody = $(document.body);
	
	mobile.BrowserCheck = {};
	// test for IE6
	mobile.BrowserCheck.IE6 = (Prototype.Browser.IE && (typeof(document.body.style.maxHeight) == "undefined"));
	
	// fire launch events for other JS.
	
	// we will fire multiple events to allow for prioritization.
	document.fire("mobile:early");
	
	// launch other scripts. Leave interpreter queue in IE6 to truly postpone actions.
	if (mobile.BrowserCheck.IE6) {
		setTimeout(function(){
			document.fire("mobile:ready");
			setTimeout(function(){
				document.fire("mobile:late");
			}, 100);
		}, 10);
	} else {
		document.fire("mobile:ready");
		setTimeout(function(){
			document.fire("mobile:late");
		}, 100);
	}
	
};
// Lifeline for load-timing issues, see globalMacros.
if (mobile._domLoaded) {
	mobile._initialize();
} else {
	document.observe("dom:loaded", mobile._initialize);
}

/**
 * Use this function to start javascript functionality on pages.
 * A javascript call wrapped by this function will
 * - execute on given event (defaults to "mobile:ready"
 * - execute only if document body has class pageClass
 * @param {Object} pageClass A body class (e.g. "home")
 * @param {Object} func The function to be executed
 * @param {Object} eventName An optional event name to execute at (defaults to "mobile:ready").
 */
mobile.initializePage = function(pageClass, func, eventName) {
	eventName = eventName || "mobile:ready";
	document.observe(eventName, function() {
		if (documentBody.hasClassName(pageClass)) {
			func();
		}
	});
};

/**
 * Utility function to handle event delegation.
 * Example:
 * 	To listen for clicks on all a.popup elements, use
 * 		mobile.observe("a.popup", "click", function() {alert("clicked!");});
 * @param {String} selector A CSS selector to determine target element.
 * @param {String} eventName The event name to observe (e.g. "click").
 * @param {Function} handler EventHandler with params (event, element).
 * @param {Element} parentElement Which parent element to observe. Defaults to document.body.
 */
mobile.observe = function(selector, eventName, handler, options) {
	options = Object.extend({
		parentElement: documentBody,
		allowNested: false,
		stopEvent: true
	}, options);
	$(options.parentElement).observe(eventName, (function(event){
		var el;
		// if (eventName == "click") debugger;
		if (options.allowNested) el = event.findElement(selector);
		else if (event.element().match(selector)) el = event.element();
		if (el && el != document) {
			if (options.stopEvent) event.stop();
			handler(event, el);
		}
	}).bindAsEventListener());
	if (mobile.isDev) console.info("Registered handler for selector %o and event %o on %o", selector, eventName, options.parentElement == documentBody ? "document body" : options.parentElement);
};

//toggle Prototype doesn't work when element has css class display: none on pageload
Element.addMethods({
	__visible: function(element) {
	    return $(element).getStyle("display") != 'none';
	},
	mobile_toggle: function(element) {
	    element = $(element);
	    Element[Element.__visible(element) ? 'hide' : '__show'](element);
	    return element;
	},
	__show: function(element) {
		element = $(element);
		element.style.display = 'block';
		return element;
	}
});

mobile.debug = {
	/**
	 * Use this function to log its usage on the console. Example: 
	 *    mobile.debug.logMethod("Object.extend");
	 * @param {String} methodName The full path to the method.
	 * @param {Object} options
	 */
	logMethod: function(methodName, options){
		var parentObject = this._getParentObject(methodName);
		if (parentObject) {
			var method = parentObject.object[parentObject.key];
			if (Object.isFunction(method)) {
				options = Object.extend({
					consolePrefix: "-- ",
					logBefore: true,
					logAfter: true
				}, options);
				var loggedMethod = method.wrap(function(){
					var args = $A(arguments);
					var proceed = args.shift();
					if (options.logBefore) console.debug(options.consolePrefix + "Executing %o with arguments %o", methodName, args);
					var returnValue = proceed.apply(null, args);
					if (options.logAfter) console.debug(options.consolePrefix + "Returning from %o with result %o", methodName, returnValue);
					return returnValue;
				});
				parentObject.object[parentObject.key] = loggedMethod
				return loggedMethod;
			}
		}
	},
	/**
	 * Pass in something like "aaa.bbb.ccc" and it will return in this case
	 * 	 {object: aaa.bbb, key: "ccc"}
	 * (if the object aaa.bbb exists).
	 * @param {String} objectPath
	 */
	_getParentObject: function(objectPath){
		var keys = objectPath.split(".");
		if (keys[0] == "window") keys.shift();
		var lastKey = keys.pop();
		try {
			var object = keys.inject(window, function(obj, key) {return obj[key];});
		} catch (e) {
			return null;
		}
		return {
			object: object,
			key: lastKey
		};
	}
}