/* FlangeLib - A JavaScript library
	adamv.com 
*/

function log(params,sep){
	var f_log = alert;
	if (sep == null) sep = "";
/* // local Firefox only	
	try {
		var consoleService = Components.classes['@mozilla.org/consoleservice;1']
                    .getService(Components.interfaces.nsIConsoleService);
		f_log = consoleSerivce.logStringMessage.bind_partial(consoleService);
	} catch(e){}
*/
	f_log(params.join(sep));
}

String.prototype.trim = function() {
	return this.replace(/^\s*(.*)/, "$1").replace(/(.*)\s*$/, "$1");}

/* // Doesn't work in Safari
String.prototype.template = function(vars){
	return this.replace( 
		/\{(\w*)\}/g,
		function(match,submatch,index){return vars[submatch];}
	) 
}
*/

String.prototype.template = function(vars){
	var _string = this;
	foreach_dict(vars, function(name,value){
		_string = _string.replace( new RegExp("\{(" + name + ")\}","g"), value);
	});
	return _string;
}

function foreach(stuff, f_each){
	if (stuff.length == null){
		f_each(stuff);
		return;
	}

	for(var i=0; i < stuff.length; i++) 
		// If f_each returns true, stop iterating
		if ( f_each(stuff[i]) ) return;
}

function foreach_dict(stuff, f_each){
	for(name in stuff)
		if ( f_each(name,stuff[name]) ) return;
}

function collect(stuff, f_each){
	var values = new Array();
	foreach(stuff, function(item){
		values.push(f_each(item));
	});
	return values;
}

/*
	Iterates the list "stuff" and creates a new list of elements X
	for which f_filter(X) is true.
	
	If f_key is given, it is used to decorate X before applying the filter.
*/
function filter(stuff, f_filter, f_key){
	f_key = f_key || function(x){return x;};
	
	var newStuff = new Array();
	foreach(stuff, function(thing){
		if (f_filter(f_key(thing))) newStuff.push(thing);
	});
	return newStuff;
}

Array.prototype.add = function() {
	var grab = this.push.bind(this);
	foreach(arguments, function(anArray){
		foreach(anArray, grab);
	});
}

Array.Create = function() {
	var newArray = new Array();
	newArray.add.apply(newArray, arguments);
	return newArray;
}

/*
	Curries a function so that it will be called with "this" set to "object".
*/
Function.prototype.bind = function(object) {
  var method = this;
  return function() {
    method.apply(object, arguments);
  }
}

/*
	Curries a function providing the first N arguments in advance.
*/
Function.prototype.partial = function() {
	var method = this;
	var _args = arguments;
	return function() {
			return method.apply(null, 
				Array.Create(_args, arguments));
		}
}

Function.prototype.bind_partial = function(object) {
	var method = this;
	var _args = Array.Create(arguments); _args.unshift();
	var _this = object;
	return function(){
		return method.apply(_this, Array.Create(_args, arguments));
	}
}

/*
	Curries a function providing the last N arguments in advance.
*/
Function.prototype.r_partial = function() {
	var method = this;
	var _args = arguments;
	return function() {
			return method.apply(null, 
				Array.Create(arguments, _args));
		}
}

/*
	Return elements in the current document with the given className.
	If tagName is given, the selection is limited to those tags.
*/
function getElementsByClass(className, tagName){
	tagName = tagName || "*";
	
	return filter(document.getElementsByTagName(tagName),
		function(elem){
			return elem.className == className;
		}
	);
}

function setStatus(text){window.status=text;return true;}

function register_external_links(){
	foreach(getElementsByClass("out","a"),  function(link){
		link['onmouseover'] = setStatus.partial("An external link to: "+ link.href);
		link['onmouseout'] = setStatus.partial("");
	});
}

function register_onload(){
	function run(f){return f();}
	var args = arguments;	

	if (!window.onload) {
		window.onload = function(){foreach(args, run);}
	}
	else {
		var old_onload = window.onload;
		window.onload = function(){
			old_onload();
			foreach(args, run);
		};
	}
}

function object_props(o){
	var s = "";
	for(var key in o){
		s+= key + ': "' + o[key] + '"\n';
	}
	return s;
}

function array_items(o){
	var items = new Array();
	if (o.length == null)
		items.push(o.toString());
	else
		for(var i=0; i < o.length; i++){
			items.push('"'+o[i].toString()+'"');
		}
	return "[" + items.join(", ") + "]";
}
