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

function slice_args(args, count){
	return Array.prototype.slice.apply(args, [count]);
}

function alert_all(params,sep){
	var f_log = alert;
	if (sep == null) sep = "";
	f_log(params.join(sep));
}

function ws_to_html(s){
	return s
		.replace(new RegExp("\n","g"), "<br>")
		.replace(new RegExp("\t","g"), "&nbsp;&nbsp;");
}

function link_to_html(s){
	var re = /(http:\/\/[\S]*)/g;
	return s
		.replace(re, "<a href='$1' target='_blank'>$1</a>");
}

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 template(s, vars){
	foreach_dict(vars, function(name,value){
		s = s.replace( new RegExp("\{(" + name + ")\}","g"), value);
	});
	return s;
}
*/

function foreach(list, f_each){
	if (list == null) return;
	
	if ((list.length == null) || (typeof list == "string")){
		f_each(list);
		return;
	}

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

function foreach_dict(object, f_each){
	for(property in object)
		// If f_each returns true, stop iterating
		if ( f_each(property,object[property]) ) return;
}

// Create a new array, calling f_each for each element of stuff	
function collect(stuff, f_each){
	var values = new Array();
	foreach(stuff, function(item){
		values.push(f_each(item));
	});
	return values;
}
	
// Create a new array of elements from stuff for which pred returns true
function filter(stuff, pred){
	var values = new Array();
	foreach(stuff, function(thing){
		if (pred(thing)) values.push(thing);
	});
	return values;
}

var List = {
	extend: function(list /*, arguments... */){
		foreach(arguments, function(anArray){
			foreach(anArray, grab);
		});
	}
};

Array.prototype.add = function() {
	var theArray = this;

	foreach(arguments, function(anArray){
		foreach(anArray, function(item){
			theArray.push(item)
		})
	})
}

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

Array.prototype.remove = function(item){
	for(var i=0; i < this.length; i++){
		if (this[i] == item){
			this.splice(i,1);
			return;
		}
	}
}

Function.prototype.partial = function(/* args */) {
	var method = this;
	var args = arguments;
	return function(){return method.apply(null,  Array.Create(args, arguments));}
}

// Could be called "bind_partial"
Function.prototype.bind = function(obj /* , args */) {
	var method = this;
	var args = slice_args(arguments,1);
	return function(){
		return method.apply(obj, Array.Create(args, arguments));
	}
}


/*
	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("");
	});
}

var Browser = {
	setStatus: function(text){
			return function(){
				window.status=text;
				return true;
			}
	},
	
	clearStatus: function(){ return Browser.setStatus("");},

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

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 using(namespaces, new_scope){
	new_scope = new_scope || window;

	var property;
	foreach(namespaces, function(namespace_){
		for(name in namespace_){
			property = namespace_[name];
			if (typeof property == "function")
				new_scope[name]=property;
		}
	})
}

var Hash = {
	dump:function(o, sep){
		sep = sep || "\n";
		var props = new Array();
		for(var key in o){
			props.push(key + ': "' + o[key]);
		}
		return props.join(sep);
	},
	
	keyName: function(obj, value){
		for(prop in obj){
			if (obj[prop]==value) return prop.toString();
		}
		
		return "";
	}
};


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(", ") + "]";
}
