
//= depends: prototype

/**
 * ZAPI
 * The main Zoocasa API namespace.
**/
var ZAPI = {
	/**
	 * Set the logging level for the ZAPI logger. This can be one of the
	 * values from ZAPI.LOG_LEVELS or any true/false expression. When true,
	 * all log messages are shown, and when false, none are show. When set to
	 * a value from ZAPI.LOG_LEVELS, only messages of that type and of lower
	 * priority are displayed.
	**/
	LOG_LEVEL: false,

	/**
	 * Logging levels available in the ZAPI logger. Levels are in order of
	 * verbosity, highest to lowest.
	**/
	LOG_LEVELS: [ 'debug3', 'debug2', 'debug1', 'debug', 'info', 'warn', 'error' ],

	VERSION: '0.0.15',

	STATUS_CODES: {
		SUCCESS:             200,
		BAD_REQUEST:         400,
		SERVER_ERROR:        500,
		BAD_KEY:             610,
		TOO_MANY_QUERIES:    620
	},

	EXTENDED_STATUS_CODES: {
		BAD_OBJECT: 710
	},

	sniffLocation: function() {
		var scripts = document.getElementsByTagName('script'),
			script = scripts[scripts.length - 1],
			location,
			retval;

		if (/^https?:\/\//i.test(script.src)) {
			location = script.src;
		}
		else {
			location = script.getAttribute('src', -1);
		}
		retval = location.parseUri();
		retval.basePath = retval.protocol + '://' + retval.host + '/';
		return retval;
	},

	resniffLocation: function() {
		return (ZAPI.LOCATION = ZAPI.sniffLocation());
	},

	sniffFeatures: function() {
		var retval = {};

		/* Detect IE version so we can deal with nonsense like PNGs and whatnot. */
		if (Prototype.Browser.IE) {
			if ((new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})")).exec(navigator.userAgent)) {
				retval.IEVersion = parseFloat(RegExp.$1);
			}
			else {
				retval.IEVersion = 0;
			}
			if ((new RegExp("Trident/([0-9]{1,}[.0-9]{0,})")).exec(navigator.userAgent)) {
   	   	 		retval.IETridentVersion = parseFloat(RegExp.$1);
			}
			else {
				retval.IETridentVersion = 0;
			}
		}

		retval.consoleProvider = (function() {
			if (typeof(console) !== 'undefined') {
				if (console['firebug']) {
					return 'firebug';
				}
				// takes care of Safari and Chrome
				else if (Prototype.Browser.WebKit) {
					return 'WebKit';
				}
				else if (Prototype.Browser.IE) {
					// debugger in IE8+?
					if (retval.IETridentVersion >= 4) {
						return 'MSIE Developer Tools';
					}
					else if (console['provider'] == 'Companion.JS') {
						return 'Companion.JS';
					}
				}
			}
			else if (typeof(google) !== 'undefined' &&
				google.maps && google.maps.Log
			) {
				return 'GLog';
			}
			else if (typeof(YAHOO) !== 'undefined') {
				try {
					var loggerContainer = new Element('div', {
						'class': 'yui-skin-sam'
					});
					var logger = new Element('div', {
						'id': 'yui-logger-container'
					});
					loggerContainer.appendChild(logger);
					document.body.appendChild(loggerContainer);
					(new YAHOO.widget.LogReader('yui-logger-container'));
					return 'YUI2';
				}
				catch (e) {}
			}

			return null;
		}());

		retval.firebug = (retval.consoleProvider == 'firebug');
		retval.console = !!retval.consoleProvider;

		return retval;
	},

	resniffFeatures: function() {
		return (ZAPI.Features = ZAPI.sniffFeatures());
	},

	/**
	 * ZAPI.log() -> null
	 *
	 * The main ZAPI logging method. If a console is enabled and the
	 * ZAPI.LOG_LEVEL is set to the appropriate level, the message is logged
	 * to the console.
	 *
	 * The first parameter to this method should be the log level, followed
	 * by the arguments you intend to pass to the console logger. See Firebug's
	 * documentation for details on that. You can also use the quick
	 * convenience methods ZAPI.debug, ZAPI.warn, etc.
	**/
	log: function() {
		if (ZAPI.Features.console && ZAPI.LOG_LEVEL) {
			if (ZAPI.LOG_LEVELS.indexOf(arguments[0]) >= ZAPI.LOG_LEVELS.indexOf(ZAPI.LOG_LEVEL)) {
				var args = $A(arguments);
				var level = args.shift();
				switch (ZAPI.Features.consoleProvider) {
					case 'firebug':
					case 'WebKit':
						if (!console[level]) {
							level = 'log';
						}
						console[level].apply(console, args);
					break;

					case 'MSIE Developer Tools':
					case 'Companion.JS':
						// ugh... IE :(
						if (!console[level]) {
							level = 'log';
						}
						var evalMe = 'console.' + level + '(' +
							$R(0, args.length - 1).collect(function(i) {
								return "args[" + i + "]";
							}).join(', ') + ')';
						eval(evalMe);
					break;

					case 'GLog':
						google.maps.Log.write(args.join(' - '));
					break;

					case 'YUI2':
						if (/^debug/.match(level)) {
							level = 'debug';
						}
						YAHOO.log(args.join(' - '), level);
					break;

					default:
						// we'll try our best and just flat out log the message.
						try {
							console.log.apply(this, args);
						}
						catch (e) {}
				}
			}
		}
	},

	debug3: function() { ZAPI.log.apply(this, [ 'debug3' ].concat($A(arguments))); },
	debug2: function() { ZAPI.log.apply(this, [ 'debug2' ].concat($A(arguments))); },
	debug1: function() { ZAPI.log.apply(this, [ 'debug1' ].concat($A(arguments))); },
	debug:  function() { ZAPI.log.apply(this, [ 'debug' ].concat($A(arguments))); },
	info:   function() { ZAPI.log.apply(this, [ 'info' ].concat($A(arguments))); },
	warn:   function() { ZAPI.log.apply(this, [ 'warn' ].concat($A(arguments))); },
	error:  function() { ZAPI.log.apply(this, [ 'error' ].concat($A(arguments))); },

	/**
	 * ZAPI.namespace(parent, namespace[, ...]) -> Object
	 * ZAPI.namespace(namespace[, ...]) -> Object
	 *
	 * Similar to YUI's YAHOO.namespace method. Creates a namespace within
	 * ZAPI for each argument provided. A reference to the last namespace
	 * created is returned.
	 *
	 * Unlike the YUI.namespace method, you can provide an Object as the first
	 * parameter to specify an arbitrary namespace outside of ZAPI. If you
	 * want to create a global namespace, you can use the window object.
	**/
	namespace: function() {
		var ns = ZAPI, n;
		var args = $A(arguments);

		if (typeof(args[0]) === 'object') {
			ns = args.shift();
		}
		else {
			ns = ZAPI;
		}

		args.each(function(a) {
			n = a.split('.');
			if (n[0] == 'ZAPI') {
				n.shift();
			}
			n.each(function(o) {
				ns[o] = ns[o] || {};
				ns = ns[o];
			});
		});
		return ns;
	},

	setAPIKey: function(key) {
		ZAPI.API_KEY = key;
		ZAPI.createDefaultAPIParams();
	},

	createDefaultAPIParams: function() {
		ZAPI.API_KEY = ZAPI.API_KEY || (ZAPI.LOCATION && ZAPI.LOCATION.query ?
			ZAPI.LOCATION.query.parseQuery().key :
			''
		);
		return (ZAPI.DEFAULT_API_PARAMS = $H({
			'ver': ZAPI.VERSION,
			'key': ZAPI.API_KEY
		}));
	}
};

/**
 * callOrRead() -> Object
 *
 * callOrRead allows you to either call the first argument if it's a function
 * or read its value. Any arguments you wish to pass to the function can be
 * supplied after the first argument. This function is aliased to $C.
**/
function callOrRead() {
	var args = $A(arguments);
	var o = args.shift();
	if (Object.isFunction(o)) {
		return o.apply(this, args);
	}
	else {
		return o;
	}
}

/** alias of: callOrRead
 * $C() -> Object
**/
var $C = callOrRead;

// Sniff out some ZAPI features:
ZAPI.resniffFeatures();
ZAPI.resniffLocation();
ZAPI.createDefaultAPIParams();

// Backwards compatibility:
if (Prototype.Browser.IE) {
	Prototype.Browser.IEVersion = ZAPI.Features.IEVersion;
	Prototype.Browser.IETridentVersion = ZAPI.Features.IETridentVersion;
}
