/*
	Behaviour v1.3 by greg harding, flightless.co.nz
	based on Behaviour v1.1, greets to ben and simon (see below)
	
	15/3/2007 - changed selector to prototype $$(selector) (1.5.0 final)
	
	11/8/2006 - refactored code from previous mods
			- return sheetid from register
			- added runSheet, actually apply a sheet to the page
			- added applySheet, apply a sheet to the page (register if it doesn't exist), returns sheetid
			- added applySheetId, apply a sheetid to the page, returns success
			- added clearSheet, clear a sheet from the registry (clears object, doesn't remove it), returns success
			- added clearSheetId, clear a sheet from the registry (clears object, doesn't remove it), returns success
	
	I'm assuming that clearing sheets would speed apply(), but these sheets could potentially
	be removed from the page as well, if required, through a remove ruleset.

	----- original header -----
	Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
	of Simon Willison.
*/   

var Behaviour = {
	list : new Array,
	
	register : function(sheet) {
		Behaviour.list.push(sheet);
		return (Behaviour.list.length-1);
	},
	
	start : function() {
		Behaviour.addLoadEvent(function() {
			Behaviour.apply();
		});
	},
	
	runSheet : function(sheet) {
		for (selector in sheet) {
			list = $$(selector); // document.getElementsBySelector(selector);
			
			if (!list) {
				continue;
			}

			for (i=0;element=list[i];i++) {
				//console.info('behaviour apply '+selector);
				sheet[selector](element);
			}
		}
	},
	
	apply : function(){
		for (h=0;sheet=Behaviour.list[h];h++) {
			Behaviour.runSheet(sheet);
		}
	},
	
	applySheet : function(specificsheet) {
		for (h=0;sheet=Behaviour.list[h];h++) {
			if (sheet==specificsheet) {
				Behaviour.runSheet(sheet);
				return h;
			}
		}
		
		var sheetid = Behaviour.register(specificsheet);
		Behaviour.applySheetId(sheetid);
		return sheetid;
	},
	
	applySheetId : function(sheetid) {
		if (sheetid<Behaviour.list.length) {
			Behaviour.runSheet(Behaviour.list[sheetid]);
			return true;
		}
		return false;
	},
	
	clearSheet : function(specificsheet) {
		for (h=0;sheet=Behaviour.list[h];h++) {
			if (sheet==specificsheet) {
				Behaviour.list[h] = {};
				return true;
			}
		}
		return false;
	},
	
	clearSheetId : function(sheetid) {
		if (sheetid<Behaviour.list.length) {
			Behaviour.list[sheetid] = {};
			return true;
		}
		return false;
	},
	
	addLoadEvent : function(func) {
		var oldonload = window.onload;
		
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	}
}

//Behaviour.start();


/*
	SmartPreload v1.2, march 2007
	v1.1, october 2006
	v1.0, august 2006
	(c) 2006 greg harding, flightless.co.nz
	
	* requires prototype 1.x (tested on 1.5)
	
	license:
		released under BSD style license
	
	description:
		preload alternate images based on class, id or source path (nb. not selector)
		class/id can match a specific img tag or child tags of matched tags (first or all, depending on greedy setting)
		preloaded images use postfix variable inserted before extension (jpg|gif) (add png if you require)
		preload static images without alternates (does not find images by class, only manual)
	
	usage:
		preload all alternate images for/under element id 'navigation'
			SmartPreload.preloadId('navigation');
		
		preload all alternate images for/under elements of class 'menu'
			SmartPreload.preloadClass('menu');
		
		preload alternate image for specific source path
			SmartPreload.preload('images/button.gif');
		
		default settings will preload '/images/button_over.jpg' for '/images/button.jpg'
		
		use another postfix for the name of alternate images
			SmartPreload.postfix = '_rolled'; // will preload '/images/button_rolled.jpg' for '/images/button.jpg'
		
		stop greedy matching, ie. only use first child img tag found, don't attempt to preload alternate images for all elements under a match
			SmartPreload.greedy = false;
		
		preload static images without alternates (eg. for swapping in images through other scripts)
			SmartPreload.preloadStatic('/images/title.jpg');
			SmartPreload.preloadStatic(imagearray); // js or prototype array
	
	issues:
		for speed it doesn't check if preloaded images already exist, so be careful with greedy classes/rules
	
	todo:
		allow tristate preload by changing postfix to array eg. _over, _on and pass boolean to preload methods
		
*/
var SmartPreload = {
	postfix: '_over',
	greedy: true,
	loadsrc: new Array(),
	classes: new Array(),
	ids: new Array(),
	preloaded: new Array(),
	preloadClass: function() {
		var classnames = $A(arguments);
		classnames.each( function(classname) {
			// preload images for tags/imgs of classname
			if (SmartPreload.classes.indexOf(classname)<0) {
				SmartPreload.classes.push(classname);
				var elements = document.getElementsByClassName(classname);
				var imgs, img;
				elements.each (function(el) {
					// use el if it's an img, if el isn't an img get first/all img tags within element
					img = el;
					if (el.tagName=='IMG') {
						SmartPreload.loadsrc.push(img.src)
					} else {
						imgs = el.getElementsByTagName('img');
						if (!SmartPreload.greedy) {
							img = imgs[0];
							if (img) SmartPreload.loadsrc.push(img.src);
						} else {
							imgs = $A(imgs);
							imgs.each (function(img) {
								SmartPreload.loadsrc.push(img.src)
							});
						}
					}
				});
				SmartPreload.preload();
			}
		});
	},
	preloadId: function() {
		var idnames = $A(arguments);
		idnames.each( function(idname) {
			// preload images for tags/imgs of id
			if (SmartPreload.ids.indexOf(idname)<0) {
				SmartPreload.ids.push(idname);
				var el = $(idname);
				if (el) {
					var imgs, img;
					// use el if it's an img, if el isn't an img get first/all img tags within element
					img = el;
					if (el.tagName=='IMG') {
						SmartPreload.loadsrc.push(img.src)
					} else {
						imgs = el.getElementsByTagName('img');
						if (!SmartPreload.greedy) {
							img = imgs[0];
							if (img) SmartPreload.loadsrc.push(img.src);
						} else {
							imgs = $A(imgs);
							imgs.each (function(img) {
								SmartPreload.loadsrc.push(img.src)
							});
						}
					}
					SmartPreload.preload();
				}
			}
		});
	},
	preload: function() {
		// preload any images in images or passed arguments
		if (arguments.length>0) {
			var args = $A(arguments);
			args.each (function(imgsrc) {
				SmartPreload.loadsrc.push(imgsrc);
			});
		}
		
		// create image, set src to alternate
		var pimg;
		SmartPreload.loadsrc.each (function(imgsrc) {
			pimg = new Image();
			pimg.src = imgsrc.replace(/\.(jpg|gif)$/i, SmartPreload.postfix+'.$1'); // add png if required
			SmartPreload.preloaded.push(pimg);
		});
		
		// clear buffer
		SmartPreload.loadsrc.clear();
	},
	preloadStatic: function() {
		// preload any non-rollover images in passed arguments
		if (arguments.length>0) {
			var args;
			if (typeof(arguments[0])=='string') {
				args = $A(arguments); // string args
			} else {
				args = $A(arguments[0]); // array arg
			}
			var pimg;
			args.each (function(imgsrc) {
				pimg = new Image();
				pimg.src = imgsrc;
				SmartPreload.preloaded.push(pimg);
			});
		}
	}
}

/*
	SimpleRollovers v1.11, march 2007
	v1.01, august 2006
	(c) 2006 greg harding, flightless.co.nz
	
	* requires prototype 1.x (tested on 1.5)
	
	license:
		released under BSD style license
	
	description:
		setup image rollovers for element, target element, input element of type image (v1.01) or the first img under element
		setup tristate rollovers/selected states
		
		will automatically attach mouseover,mouseout events to object
		
		automatically preload rolled images for rollover/trirollover
	
	usage:
		simple rollover from img element or element with child img element
			el.initRollover()
		
		simple rollover from any element to target img element or target element with child img element
			el.initRollover(target)
		
		rollover from img element or element with child img element with specific rolled image to use (set target to null if not required)
			nb. assumes the target image is in the same directory as the source image
			el.initRollover(target, true, rolledimagename)
		
		to rollover/rollout
			el.rollover()
			el.rollout()
		
		simple rollover without mouse events automatically attached (set target to null if not required)
			el.initRollover(target, false)
	
	issues:
		none, could extend with multiple targets to roll

*/
Element.SimpleRollovers = {
	initRollover: function(el, target, autoattach, rolledimage) {
		// init rollover for this element or target element, or the first img under element
		var roimg = el;
		if (target) {
			// target element to rollover
			roimg = target;
		}
		if (roimg.tagName=='IMG' || (roimg.tagName=='INPUT' && roimg.type.toLowerCase()=='image')) {
			// roll this element
			el.img = roimg;
		} else {
			// roll first img under element
			var findimg = roimg.getElementsByTagName('IMG')[0];
			if (!findimg) return;
			el.img = findimg;
		}
		
		// save rollover target img srcs
		el.img.src_ = el.img.src;
		if (rolledimage) {
			el.img.src_o = el.img.src.replace(/(\w+)\.(jpg|gif)$/, rolledimage);
		} else {
			el.img.src_o = el.img.src.replace(/\.(jpg|gif)$/, '_over.$1');
		}
		el.img.src_on = el.img.src_o; // default img tri state
		
		// preload rollover image
		SmartPreload.preloadStatic(el.img.src_o);
		
		// tri state
		el.img.src_tri = false;
		
		// delay
		el.delay = false;
		
		// attach mouse events
		if (autoattach==undefined) autoattach=true;
		if (autoattach) {
			el.oldonmouseover = el.onmouseover;
			el.oldonmouseout = el.onmouseout;
			
			el.onmouseover = function() {
				if (el.oldonmouseover) el.oldonmouseover();
				this.rollover();
			}
			
			el.onmouseout = function() {
				if (el.oldonmouseout) el.oldonmouseout();
				this.rollout();
			}
		}
	},
	initTriRollover: function(el, target, autoattach) {
		// init tristate rollover for this element or target element, or the first img under element
		// init normal rollover
		if (!target) target=null;
		if (!autoattach) autoattach=null;
		el.initRollover(target, autoattach);
		
		// add img tri state
		el.img.src_on = el.img.src.replace(/\.(jpg|gif)$/, '_on.$1');
		
		// preload trirollover image
		SmartPreload.preloadStatic(el.img.src_on);
	},
	rollover: function(el) {
		if (el.delay) window.clearInterval(el.delay);
		el.delay = false;
		if (!el.img.src_tri) el.img.src = el.img.src_o;
	},
	rollout: function(el) {
		if (el.delay) window.clearInterval(el.delay);
		el.delay = false;
		if (!el.img.src_tri) el.img.src = el.img.src_;
	},
	rolloutDelayed: function(el, delayms) {
		if (!delayms) delayms = 500;
		el.delay = window.setInterval(ro, delayms);
		function ro() { el.rollout() };
	},
	trion: function(el) {
		el.img.src_tri = true;
		el.img.src = el.img.src_on;
	},
	trioff: function(el) {
		el.img.src_tri = false;
		el.img.src = el.img.src_;
	}
}
Element.addMethods(Element.SimpleRollovers);

/*
	SimpleConsole
*/
var console;
function initConsole(el) {
	if (console!=undefined && console.log!=undefined) {
		console.log('console active'); // firebug
	} else {
		if (!el) el=$(document.getElementsByTagName('BODY')[0]);
		new Insertion.Bottom(el,'<div id="console" style="border: 1px solid #cccccc; height: 100px; overflow: auto;"></div><div id="consoleclear">clear console</div>');
		
		console = new SimpleConsole(); // onscreen
	}
}

var SimpleConsole = Class.create();
SimpleConsole.prototype = {
	initialize: function(elname) {
		if (elname==undefined || elname=='') elname='console';
		this.output = $(elname);
		if (this.output) {
			this.output.innerHTML = 'console active';
			this.count = 0;
			var rules_console = {
				'#consoleclear': function(el) {
					el.onclick = function() {
						console.clear();
					}
				}
			}
			Behaviour.applySheet(rules_console);
		}
	},
	trace: function(msg) {
		this.count++;
		this.output.innerHTML = '('+this.count+') '+msg+'<br />'+this.output.innerHTML;
	},
	log: function(m) {
		this.trace(m);
	},
	debug: function(m) {
		this.trace('[debug] '+m);
	},
	info: function(m) {
		this.trace('[info] '+m);
	},
	warn: function(m) {
		this.trace('[warn] '+m);
	},
	error: function(m) {
		this.trace('[error] '+m);
	},
	clear: function() {
		this.output.innerHTML = '';
	}
};

/*
	Tooltip
	<div id="tooltip"><span class="output"></span></div>
*/
var tooltip;
function initTooltip() {
	tooltip = new Tooltip();
	
	var rules_tooltip = {
		'.tooltip': function(el) {
			tooltip.addTooltip(el);
		}
	}
	
	Behaviour.clearSheetId(Behaviour.applySheet(rules_tooltip));
}

var Tooltip = Class.create();
Tooltip.prototype = {
	display: null,
	output: null,
	initialize: function(el, usetooltipname) {
		if (!el) el=$(document.getElementsByTagName('BODY')[0]);
		if (!usetooltipname) usetooltipname='tooltip';
		this.tooltipname = usetooltipname;
		new Insertion.Bottom(el, '<div id="'+this.tooltipname+'"><div class="wrapper"><div class="output"></div></div></div>');
		
		this.display = $(this.tooltipname);
		this.output = document.getElementsByClassName('output', this.display)[0];
	},
	addTooltip: function(el) {
		el = $(el);
		if (el.title!='') {
			el.tooltip = this;
			el.message = el.title;
			el.removeAttribute("title");
			
			// element events
			el.onmouseover = this.showTooltip;
			el.onmouseout = this.hideTooltip;
		}
	},
	showTooltip: function(ev) {
		// update message
		this.tooltip.output.innerHTML = this.message;
		
		// get position, offset to centre of target, move up by height of tooltip
		var pos = Position.cumulativeOffset(this);
		var dimensions = this.getDimensions();
		var offsetLeft=0;
		if (dimensions.width) {
			offsetLeft = (dimensions.width/2)-8;
		}
		var posLeft = pos[0]+offsetLeft;
		
		dimensions = this.tooltip.display.getDimensions();
		var offsetTop=0;
		if (dimensions.height) {
			offsetTop = -dimensions.height-2;
		}
		var posTop = pos[1]+offsetTop;
		
		// set position
		this.tooltip.display.setStyle({
			left: posLeft+'px',
			top: posTop+'px'
		});
		
		// display
		this.tooltip.display.addClassName('on');
	},
	hideTooltip: function() {
		this.tooltip.output.innerHTML = '';
		this.tooltip.display.removeClassName('on');
	},
	removeToolTip: function(el) {
		el = $(el);
		el.remove();
		delete this;
	}
}

/*
	SimpleMenu v1.0, august 2006
	v1.1, august 2007
	(c) 2007 greg harding, flightless.co.nz
	
	* requires prototype 1.x (tested on 1.5)
*/
var SimpleMenu = {
	lastmenu: {menubuttonid:null, menuid:null, mbrollover:null},
	menuOn: function (menubuttonid, menuid, mbrollover, mbclass) {
		var menubutton = $(menubuttonid);
		var menu = $(menuid);
		
		// clear delay
		if (menu.delay) window.clearInterval(menu.delay);
		menu.delay = false;
		
		// show
		if (mbrollover) menubutton.rollover(); // button state
		if (!mbclass) {
			menubutton.menuclass = null;
		} else {
			menubutton.menuclass = mbclass;
			menubutton.addClassName(mbclass);
		}

		menu.addClassName('hover'); // menu state
		
		// save last menu
		SimpleMenu.lastmenu.menubuttonid = menubuttonid;
		SimpleMenu.lastmenu.menuid = menuid;
		SimpleMenu.lastmenu.mbrollover = mbrollover;
	},
	menusOff: function (menuarray) {
		if (menuarray) {
			// turn off selected menus
			menuarray = $A(menuarray);
			menuarray.each( function(menuinfo) {
				SimpleMenu.menuOff(menuinfo[0],menuinfo[1],menuinfo[2]);
			});
		} else if (SimpleMenu.lastmenu.menuid) {
			// turn off last menu
			SimpleMenu.menuOff(SimpleMenu.lastmenu.menubuttonid, SimpleMenu.lastmenu.menuid, SimpleMenu.lastmenu.mbrollover);
		}
	},
	menuOff: function (menubuttonid, menuid, mbrollover) {
		var menubutton = $(menubuttonid);
		var menu = $(menuid);
		
		// clear delay
		if (menu.delay) window.clearInterval(menu.delay);
		menu.delay = false;
		
		// hide
		if (mbrollover) menubutton.rollout(); // button state
		if (menubutton.menuclass) {
			menubutton.removeClassName(menubutton.menuclass);
			menubutton.menuclass = null;
		}
		menu.removeClassName('hover'); // menu state
		
		// remove last menu
		SimpleMenu.lastmenu.menubuttonid = null;
		SimpleMenu.lastmenu.menuid = null;
		SimpleMenu.lastmenu.mbrollover = null;
	},
	menuOffDelayed: function (menubuttonid, menuid, mbrollover) {
		var menu = $(menuid);
		
		// clear delay, set new delay for off
		if (menu.delay) window.clearInterval(menu.delay);
		menu.delay = window.setInterval(function() { SimpleMenu.menuOff(menubuttonid, menuid, mbrollover) }, 500);
	}
}

/*
	general functions
*/
function stopEvent(ev) {
	if (!ev) ev = window.event;
	Event.stop(ev);
}

/*
	mm code (if required), tweaked
*/
function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}

function MM_swapImageFast() { //v1.0
  var i,j=0,x,a=MM_swapImageFast.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=a[i])){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}
