/* ======================================================================== */

// IE/win background image flicker fix
// http://evil.che.lu/2006/9/25/no-more-ie6-background-flicker
try { document.execCommand('BackgroundImageCache', false, true); } catch(e) {}

/* ======================================================================== */

/* NOTE: the following code was extracted from the UFO source and extensively reworked/simplified */

/* Unobtrusive Flash Objects (UFO) v3.20 <http://www.bobbyvandersluis.com/ufo/>
	Copyright 2005, 2006 Bobby van der Sluis
	This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/

function createCSS(selector, declaration) {
	// test for IE
	var ua = navigator.userAgent.toLowerCase();
	var isIE = (/msie/.test(ua)) && !(/opera/.test(ua)) && (/win/.test(ua));

	// create the style node for all browsers
	var style_node = document.createElement("style");
	style_node.setAttribute("type", "text/css");
	style_node.setAttribute("media", "screen"); 

	// append a rule for good browsers
	if (!isIE) style_node.appendChild(document.createTextNode(selector + " {" + declaration + "}"));

	// append the style node
	document.getElementsByTagName("head")[0].appendChild(style_node);

	// use alternative methods for IE
	if (isIE && document.styleSheets && document.styleSheets.length > 0) {
		var last_style_node = document.styleSheets[document.styleSheets.length - 1];
		if (typeof(last_style_node.addRule) == "object") last_style_node.addRule(selector, declaration);
	}
};


/* ======================================================================== */
/* ======================================================================== */


// standard DOM ready functionality, made available via Event.onReady()
Object.extend(Event, {
	_domReady : function() {
		if (arguments.callee.done) { return; }
		arguments.callee.done = true;
		if (this._timer) { clearInterval(this._timer); }
		this._readyCallbacks.each(function(f) { f(); });
		this._readyCallbacks = null;
	},

	onReady : function(f) {
		if (!this._readyCallbacks) {
			var domReady = this._domReady.bind(this);

			if (document.addEventListener) {
				document.addEventListener("DOMContentLoaded", domReady, false);
			}

			/*@cc_on @*/
			/*@if (@_win32)
				document.write("<script id=__ie_onload defer src=" + (location.protocol == "https:" ?  "https://" : "") + "javascript:void(0)><\/script>");
				document.getElementById("__ie_onload").onreadystatechange = function() {if (this.readyState == "complete") domReady(); };
			/*@end @*/

			if (/WebKit/i.test(navigator.userAgent)) {
				this._timer = setInterval(function() { 
					if (/loaded|complete/.test(document.readyState)) { domReady(); }
				}, 10);
			}

			Event.observe(window, 'load', domReady);
			Event._readyCallbacks =  [];
		}

		Event._readyCallbacks.push(f);
	}
});

/* ======================================================================== */

// simple return false function
Object.extend(Prototype, { False : function(){ return false; } });

/* ======================================================================== */

// looks for IE6 so we can set display properties like min-height vs. height
Object.extend(Prototype.Browser, {
	IE6 : (function(){
		return (/msie 6/i.test(navigator.userAgent)) && !(/opera/i.test(navigator.userAgent)) && (/win/i.test(navigator.userAgent));
	})()
});

/* ======================================================================== */

// look for old, bug-ridden versions of WebKit
Object.extend(Prototype.Browser, {
	WebkitOld : (function(){
		// Safari: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3
		// WebKit (as of 2007-07-04): Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3
		var regex = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
		return (regex && regex.length == 2) ? (parseInt(regex[1]) <= 419) : false;
	})()
});

// this fixes the constructor problem in old versions of WebKit
function fixWebKitInheritanceBug(obj) {
	if (Prototype.Browser.WebkitOld) obj.prototype.constructor = obj;
}

/* ======================================================================== */

Object.extend(String.prototype, {
	getHash : function() {	
		var idx = this.indexOf("#");
		return (idx >= 0 ) ? this.substring(idx + 1) : null;
	},

	convertLineBreaks : function() {
		return this.replace(/\n/g, "\<br \/\>");
	},

	parseTags : function(separator) {
		var current_tags = (this == "") ? [] : this.split(separator || ',');
		return current_tags.map(function(val){ return val.strip(); }).without('').uniq();
	},

  urlEncode: function() {
    return this.replace(/([^A-Za-z0-9])/g,
			function (matched_substring, paren1, match_offset, orig_string) {
	        return "%" + paren1.charCodeAt(0).toString(16).toUpperCase();
	     }
		);
  },

	truncateByWord: function(num_chars) {
		if (this.length <= num_chars) { return this; }

		var word_break_position = -1;
		for (i=0; i < num_chars; i++) {
			if (this.charAt(i).match(/[.,;!? ]/)) { word_break_position = i; }
		}
		if (word_break_position == -1) { word_break_position = size - 1; }

		return this.substring(0, word_break_position) + '&hellip;';
	},

	isNumber : function() {
		var s = this.toString();
		return s.match(/^\d+$/);
	}

});

/* ======================================================================== */

// convenience function: $$ with scope as first arg
function $$S() {
	var args = $A(arguments), scope = args.shift();
  return Selector.findChildElements(scope, $A(args));
}

/* ======================================================================== */

// returns form elements by form_name and element name
// useful for returning a group of radio buttons as an array
function $FE(form_name, element_name) {
	if ( (typeof(form_name) != 'string') || typeof(element_name) != 'string' ) { return; }

	var f = document.forms[form_name] || $$("FORM#" + form_name)[0];
	var elements = f.elements[element_name];

	if (!f || !elements) {
		return null;
	
	} else {
		return elements;
	}
}

/* ======================================================================== */

// fixes browsers which don't implement <OPTION disabled="disabled">
Event.onReady(function(){
	function fixDisabledOptions() { $A(this.options).each(function(opt) { if ($(opt).disabled) opt.selected = false; }); }
	$$("SELECT").each(function(sel){ Event.observe(sel, 'change', fixDisabledOptions.bind(sel)); });
});

/* ======================================================================== */

// site namespace constructor
function Site(globals) {

	this.GLOBALS = Object.extend({
		active_class : "Active",
		expanded_class : "Expanded",
		disabled_class : "Disabled",
		deleted_class : "Deleted",
		selected_class : "Selected",
		hover_class : "Hover",
		link_class : "Link",
		dhtml_link_class : "LinkDHTML",
		img_path : "/images/",
		ajax_update_delay : 100 // ms
	}, globals || { });

	/* ---------------------------------------------------------------------- */

	// boolean; to enable console debugging, pass in "DEBUG" as a query param
	this.DEBUG = function() {
		var qs = window.location.search.toQueryParams();
//		console.log("Object.keys(qs).indexOf(\"DEBUG\") = " + Object.keys(qs).indexOf("DEBUG"));
		return (Object.keys(qs).indexOf("DEBUG") > -1) || false; // NOTE: make sure this is false for production
	}();

	// tiny debug wrapper (being nice to IE/Win)
	this.debug = function(msg) {
		// bail out if debugging is off
		if (!this.DEBUG) { return; }

		// accept an array of strings and use them as lines
		if (msg instanceof Array) {
			msg = msg.join("\n");
		}

		try {
			// ff and safari go here
			console.log(msg);

		} catch(e) {
			// IE gets this

			// open the win if no win exist
			if (!this.debug_win) {
				this.debug_win = window.open("","","");
				this.debug_win.document.open();
			}

			// simple HTML regex
			msg = msg.replace(/</g, "&lt;");
			msg = msg.replace(/>/g, "&gt;");

			// user may have closed the window, so reopen if necessary
			try {
				this.debug_win.document.write("");
			} catch(e) {
				this.debug_win = window.open("","","");
				this.debug_win.document.open();			
			}

			// finally output the msg
			this.debug_win.document.write("<pre style='font-size: 80%; margin: .5em 0 2em 0;'>" + msg + "</pre>");

		}
	}; // END: debug()

	/* ---------------------------------------------------------------------- */

	this.addFeature = function(feature_name, config) {
		// don't add the same feature twice
		if (this.Features[feature_name]) return;

		// take care of 'special' methods
		delete config.widget_instances;
		delete config.storeWidgetInstance;
		delete config.removeWidgetInstance;

		// add the feature
		this.Features[feature_name] = Object.extend({
			widget_instances : { },

			storeWidgetInstance : function(id, widget, overwrite) {	
				if (typeof(this.widget_instances[id]) === 'undefined') {
					this.widget_instances[id] = widget;
					return true;

				} else if (overwrite === true) {
	//			this.debug(["hash \"" + id + "\" already exists in elements... OVERWRITING", "this.elements[" + id + "] = " + this.elements[id].toString() ]);
					this.widget_instances[id] = widget;
					return true;

				} else {
	//			this.debug(["hash \"" + id + "\" already exists in elements", "this.elements[" + id + "] = " + this.elements[id].toString() ]);
					return false;
				}
			}, // END: store()

			removeWidgetInstance : function(id) {
				if (typeof(this.widget_instances[id]) !== 'undefined') {
					delete this.widget_instances[id];
					return true;

				} else {
	//			this.debug("hash \"" + id + "\" not found");
					return false;
				}
			},

			initialize : Prototype.emptyFunction,

			setupElements : Prototype.emptyFunction,

			_setupElements : function(root_node) {
				// accept an aribitrary root_node (for use with AJAX updates)
				root_node = $(root_node) || document;

//				console.log("setupElements(" + root_node + ")");

				this.setupElements(root_node);
			}

		}, config || { });
	
		// initialize it
		this.Features[feature_name].initialize();

		// if domReady wasn't called yet, call setupElements on domReady
		if (!Event._domReady.done) {
			Event.onReady(this.Features[feature_name]._setupElements.bind(this.Features[feature_name]));

		// if it's after domReady, then just call our function
		} else {
			this.Features[feature_name]._setupElements();
		}

	};

	this.Features = { };

}

/* ======================================================================== */

var PageWidget = Class.create();
PageWidget.CONFIG = { };

Object.extend(PageWidget.prototype,  {
	node : null,

	// basic, useless initialize method
	initialize : function(id, options) {
		this.node = $(id);

		this.setOptions(options);
	},

	setOptions : function(config) {
		this.CONFIG = Object.extend(Object.clone(this.constructor.CONFIG), config || {});
	}
});

fixWebKitInheritanceBug(PageWidget);
