/* Interaction Interface Library
 * Copyright (c) 2008 Interaction Initiative Inc.
 * All rights reserved.
 */

var iiMenu = function(id, style) {
	this._id = id;
	this._style = style;
	this._init($(id));
}

iiMenu.prototype = {
	topMenuList: null,
	subMenuList: [],
	currentItem: null,
	length: 0,

//	_private:
	_init: function(ul) {
		ul.menuId = this._id;
		ul.hierarchy = 0;

		var list = this.topMenuList = select_element(ul.childNodes);
		for (var i = 0; i < list.length; i++) {
			var li = list[i];
			this._addAttribute(ul, li, i + 1);

			li.menuNodeType = 'mainMenu';
if (li.subMenu)		
			li.menuItem.onclick = function(e) {
				AlternateStyleSheet.check();
				this.focus();
				return stopEventPropagation(e);
			};
		}
		this.length = list.length;
		Event.observe(document, 'click', this.hide.bind(this));
	},

	_addAttribute: function(parent, li, index) {
		li.menuId = parent.menuId + '-' + index;
		li.hierarchy = parent.hierarchy + 1;
		li.menuNodeType = 'menuItem';
		li.menuGroup = (li.hierarchy == 1) ? index : parent.menuGroup;
		li.menuIndex = index - 1;
		li.subMenu = null;
		li.chidMenu = null;
		li.parentMenu = (li.hierarchy == 1) ? null : parent;

		var a = li.getElementsByTagName('A')[0];
		if (a) {
			li.menuItem = a;
			a.menuIndex = li.menuIndex;

			var kbd = a.getElementsByTagName('KBD')[0];
			if (kbd) {
				li.shortCut = kbd.firstChild.nodeValue;
			}
//			a.onclick = function() { return false; }
			a.onfocus = this._select.bind(this, a);
			if (li.hierarchy > 1 || this._style.mouseoverEnabled)
///				a.onmouseover = function() { this.focus(); };
				a.onmouseover = this._select.bind(this, a);
		}
		var ul = li.getElementsByTagName('UL')[0];
		if (ul) {
			var menuList = select_element(ul.childNodes);
			if (menuList.length > 0) {
				this.subMenuList.push(ul);

				li.subMenu = ul;
				li.childMenu = menuList;
				li.menuNodeType = 'menuGroup';

				for (var i = 0; i < menuList.length; i++) {
					this._addAttribute(li, menuList[i], i + 1);
				}
			}
		}
		this._style.setMenuItemStyle(li);
	},

	_select: function(a) {
		if (this.currentItem)
			this._style.blur(this.currentItem, this);

		var item = this.currentItem = a.parentNode;
		this._style.focus(item, this);

		this._hide(item.hierarchy);
		if (item.subMenu && !item.menuDisabled) {
			this._style.showMenu(item.subMenu, this);
		}
		iiKey.setActiveListener(this);
	},

	_hide: function(hierarchy) {
		for (var i = 0, menu; menu = this.subMenuList[i]; i++) {
			if (menu.parentNode.hierarchy >= hierarchy) {
				this._style.hideMenu(menu, this);
			}
		}
	},

	_setMenuAction: function(menu, action) {
		for (var i = 0; i < menu.length; i++) {
			if (menu[i].menuItem) {
				menu[i].menuItem.onclick = function(e) {
					AlternateStyleSheet.check();
					return action.call(this, e);
				}
			}
			if (menu[i].childMenu) {
				this._setMenuAction(menu[i].childMenu, action);
			}
		}
	},

//	public:

	setMenuAction: function(group, action) {
		var menu = this.topMenuList[group-1];
		if (menu && menu.childMenu) {
			this._setMenuAction(menu.childMenu, action);
		}
	},
	
	hide: function() {
		var item = this.currentItem; 
		if (item) {
			item.menuItem.blur();
			this._style.blur(item, this);
		}
		this.currentItem = null;
		this._hide(0);
	},
	
	invoke: function(item) {
if (item.menuDisabled) return false;
		var event = {};
		item.menuItem.onclick(event);
		if (event.cancelBubble)
			return false;
		this.hide();
		return true;
	},

	_shortcut: function(key, menu) {
		try {
			for (var i = 0; i < menu.length; i++) {
				if (key == menu[i].shortCut) {
					if (menu[i].subMenu) {
						menu[i].menuItem.focus();
					} else if (menu[i].menuItem && !iiWidget.effect.busy) {//TODO
						this.invoke(menu[i]);
					}
					return menu[i];
				}
			}
		} catch (e) {
			//alert(e.message + '\n' + this.currentItem);
		}
		return null;
	},
	
	onkeydown: function(e, code, shift, ctrl, alt) {
		if (shift && code != Event.KEY_TAB || ctrl || alt) return true;

		var key = String.fromCharCode(code);
		var item = this.currentItem;
		if (item == null && code != Event.KEY_TAB) {
			return this._shortcut(key, this.topMenuList) ? false : true;
		}
		var next = null;
		var index;
		switch (code) {
		case Event.KEY_UP:
			if (item.parentMenu == null){
				if (item.childMenu) next = item.childMenu[item.childMenu.length - 1];
			} else{
				if ((index = item.menuIndex - 1) < 0) index = item.parentMenu.childMenu.length - 1;
				next = item.parentMenu.childMenu[index];
			}
			break;
		case Event.KEY_DOWN:
			if (item.parentMenu == null){
				if (item.childMenu) next = item.childMenu[0];
			} else{
				index = (item.menuIndex + 1) % item.parentMenu.childMenu.length;
				next = item.parentMenu.childMenu[index];
			}
			stopEventPropagation(e)

			break;
		case Event.KEY_LEFT:
			if (item.parentMenu && item.parentMenu.menuNodeType != 'mainMenu') {
				next = item.parentMenu;
			} else {
				if ((index = item.menuGroup - 2) < 0) index = this.topMenuList.length - 1;
				next = this.topMenuList[index];
			}
			break;
		case Event.KEY_RIGHT:
			if (item.menuNodeType == 'menuGroup') {
				next = item.childMenu[0];
			} else {
				index = item.menuGroup % this.topMenuList.length;
				next = this.topMenuList[index];
			}
			break;
		case Event.KEY_TAB:
			if (item == null) {
				next = this.topMenuList[shift ? this.topMenuList.length - 1 : 0];
			} else {
				index = shift ? item.menuGroup - 2 : item.menuGroup;
				if (index < 0 || index >= this.topMenuList.length) {
					this.hide();
					return true;
				}
				next = this.topMenuList[index];
			}
			break;

		case Event.KEY_RETURN:
			if (item.menuNodeType == "menuGroup") {
				item.childMenu[0].firstChild.focus();
				return false;
			}
			if (item.menuNodeType == "menuItem") {
				this.invoke(item);
//				return false;
				return stopEventPropagation(e);
			}
			return true;
		case Event.KEY_ESC:
			this.hide();
			return true;
		}
		if (next) {
			next.firstChild.focus();
			return false;
		}
		if (item.childMenu && this._shortcut(key, item.childMenu)) {
			return false;
		}
		if (item.parentMenu && this._shortcut(key, item.parentMenu.childMenu)) {
			return false;
		}
		return true;
	}
}

var iiKey = {
	listeners: [],
	active: null,
	cursorKey: [Event.KEY_UP, Event.KEY_DOWN, Event.KEY_LEFT, Event.KEY_RIGHT, Event.KEY_RETURN],
	event: null,

	onkeydown: function(e) {
		var listener = this.active;
		if (!listener) return true;

		AlternateStyleSheet.check();

		e = e || window.event;
		iiKey.event = e;
		var code = e.keyCode;
		if (code >= 96 && code <= 105) code -= 48; //tenkey
		var broadcast = this.cursorKey.indexOf(code) == -1;
		while (true) {
			var bubble = listener.onkeydown(e, code, e.shiftKey, e.ctrlKey, e.altKey);
			if (bubble == false) {
				if (code == Event.KEY_TAB) {
					this.active = listener;
				}
				break;
			}
			if (!broadcast) break;

			var index = (listener.keyListenerIndex + 1) % this.listeners.length;
			if (index == this.active.keyListenerIndex) {
				break;
			}
			listener = this.listeners[index];
		}
		iiKey.event = null;
		return (code == Event.KEY_TAB) ? stopEventPropagation(e) : bubble;
	},
	
	getActiveListener: function() {
		return this.active;
	},

	setActiveListener: function(listener) {
		this.active = listener;
	},

	addListener: function(listener) {
		listener.keyListenerIndex = this.listeners.length;
		this.listeners.push(listener);
		if (listener.keyListenerIndex == 0) {
			this.active = this.listeners[0];
			Event.observe(document, 'keydown', this.onkeydown.bind(this));
		}
	},

	removeListener: function(listener) {
		//TODO
		var len = this.listeners.length;
		var index = -1;
		for (var i = 0; i < len; i++) {
			if (this.listeners[i] == listener)
				index = i;
			if (index >= 0 && (this.listeners[i] = this.listeners[i + 1])) 
				this.listeners[i].keyListenerIndex = i;
		}
		if (len > 0)
			this.listeners.length = len - 1;
		if (this.active == listener && index >= 0)
			this.active = this.listeners[(index + len) % len]; 
	},

	replaceListener: function(_old, _new) {
		var len = this.listeners.length;
		for (var i = 0; i < len; i++) {
			if (this.listeners[i] == _old) {
				this.listeners[i] = _new;
				_new.keyListenerIndex = _old.keyListenerIndex;

				if (this.active == _old)
					this.active = _new;
				return;
			}
		}
		this.addListener(_new);
	}
}

var iiDrag = {
	onDrag: null,
	onDrop: null,
	x: 0,
	y: 0,

	init: function(e, onDrag, onDrop, cursor) {
		e = e || window.event;
		this.x = e.clientX;
		this.y = e.clientY;
		this.onDrag = onDrag;
		this.onDrop = onDrop;

		document.body.style.cursor = cursor || 'move';
		document.body.onmousemove = iiDrag.drag;
		document.body.onmouseup = iiDrag.drop;
	},

	drag: function(e) {
		e = e || window.event;
		var dx = e.clientX - iiDrag.x;
		var dy = e.clientY - iiDrag.y;
		if (iiDrag.onDrag) return iiDrag.onDrag(dx, dy, e); 
	},

	drop: function(e) {
		document.body.style.cursor = 'default';
		document.body.onmousemove = null;
		document.body.onmouseup = null;
		if (iiDrag.onDrop) return iiDrag.onDrop(e); 
	}
}

var iiEffect = Class.create();

iiEffect.prototype = {
	initialize: function(element, start, end, duration, interval) {
		this.element = element;
		this.start = start;
		this.end = end;

		this.duration = duration || 1000;
		this.interval = interval || 50;
		this.counter = 0;

		if (this.element) {
			this.init();
			this.timer = setInterval(this.handler.bind(this), this.interval);
			this.element.effect = this;
		}
	},

	handler: function() {
		var time = ++this.counter * this.interval;

		this.effect(time);

		if (time >= this.duration) {
			this.cancel();

			if (this.onStop) this.onStop();
		}
	},

	cancel: function() {
		clearInterval(this.timer);
		this.element.effect = undefined;
	},

	onStop: function() {
	},

	linear: function(x1, x2, time, duration) {
		time = time || this.counter * this.interval;
		duration = duration || this.duration;
		return x1 + (x2 - x1)*time/duration;
	},

	init: function() {},
	effect: function(time) {}
}

iiEffect.Alpha = Class.create();
iiEffect.Alpha.prototype = Object.extend(new iiEffect, {
	init: function() {
		Element.setOpacity(this.element, this.start/100);
	},
	effect: function(time) {
		Element.setOpacity(this.element, this.linear(this.start, this.end, time)/100);
	}
});

iiEffect.Gray = Class.create();
iiEffect.Gray.prototype = Object.extend(new iiEffect, {
	init: function() {
		this.element.style.color = this.hex(this.start);
		this.element.style.backgroundColor = this.hex(this.end);
	},

	effect: function(time) {
		var color = this.linear(this.start, this.end);
		var bg = this.linear(this.end, this.start);
		this.element.style.color = this.hex(color);
		this.element.style.backgroundColor = this.hex(bg);
	},

	hex: function(dec) {
		var h = Math.floor(dec).toString(16);
		return '#' + h + h + h;
	}
});


iiEffect.scroll = Class.create();
iiEffect.scroll.prototype = Object.extend(new iiEffect, {
	init: function() {
//		this.start = this.element == window ? (this.start || 0) : this.element.scrollTop;
		var top = document.body.scrollTop || document.documentElement.scrollTop;
		this.start = this.element == window ? top : this.element.scrollTop;
		this.end -= this.start;
	},
	effect: function(time) {
		var t = time/this.duration*2; // easeInOutQuart
		var top = this.start + this.end/2 * (t < 1 ? t*t*t*t : 2 - (t -= 2)*t*t*t);
		if (this.element == window)
			window.scrollTo(0, top);
		else
			this.element.scrollTop = top;
	}
});

var iiPersistence = {
	expire: 30,
	path: null,

	set: function(name, value) {
		var cookie = name + '=' + this.encode(value);
		if (this.path) {
			cookie += ' ;path=' + this.path;
		}
		if (this.expire) {
			var d = new Date();
			d.setTime(d.getTime() + this.expire*24*60*60*1000);
			cookie += ' ;expires=' + d.toGMTString();
		}
		document.cookie = cookie;
	},
	get: function(name) {
		var cookies = document.cookie.split(';');
		for (var i = 0; i < cookies.length; i++) {
			var cookie = cookies[i].split('=');
			if (cookie[0].strip() == name && cookie[1]) {
				return this.decode(cookie[1]).strip();
			}
		}
		return null;
	},
	clear: function() {
		var d = new Date();
		d.setTime(0);
		var expire = ';expires=' + d.toGMTString();
//		if (!confirm(expire)) return;
		var cookies = document.cookie.split(';');
		for (var i = 0; i < cookies.length; i++) {
			document.cookie = cookies[i] + expire;
		}
	},
	
	encode: function(s) {
		return (encodeURIComponent || encodeURI || escape)(s);
	},
	decode: function(s) {
		return (decodeURIComponent || decodeURI || unescape)(s);
	}
}

var AlternateStyleSheet = {
	active: null,

	init: function() {
		this.disableAll();
	},

	disableAll: function() {
		var link, tags = document.getElementsByTagName('link');
		for (var i = 0; link = tags[i]; i++) {
			var rel = link.getAttribute('rel');
			if (rel && rel.indexOf('style') != -1 && link.getAttribute('title')) {
				link.disabled = true;
			}
		}
	},

	setActive: function(title) {
		var link, tags = document.getElementsByTagName('link');
		var found = false;
		for (var i = 0; link = tags[i]; i++) {
			var rel = link.getAttribute('rel');
			if (rel && rel.indexOf('style') != -1 && link.getAttribute('title')) {
				link.disabled = link.getAttribute('title') != title;
				found = found || link.disabled == false;
//				if (Prototype.Browser.WebKit)
//					link.setAttribute('rel', (link.disabled ? 'alternate ' : '') + 'stylesheet');
			}
		}
		if (found) this.active = title;
		return found;
	},

	getActive: function() {
		var link, tags = document.getElementsByTagName('link');
		for (var i = 0; link = tags[i]; i++) {
			var title = link.getAttribute('title');
			var rel = link.getAttribute('rel');
			if (rel && rel.indexOf('style') != -1 && title && !link.disabled) {
				return title;
			}
		}
		return null;
	},
	add: function(url, title, media) {
		//document.createStyleSheet(url);
		var link = document.createElement('link');
		link.rel = 'stylesheet';
		link.type = 'text/css';
		link.href = url;
		link.title = title;
		link.media = media || 'all';
		document.getElementsByTagName('head')[0].appendChild(link);
	},
	check: function() {
		var title = AlternateStyleSheet.getActive();
		var active = AlternateStyleSheet.active;
		if (title != active)
			AlternateStyleSheet.onchange(title, active);
		  
	},
	onchange: function(title, old) {
		//alert(title)
	},
	
	getIndex: function(title) {
		title = title || this.active;
		var index = -1;
		var link, tags = document.getElementsByTagName('link');
		for (var i = 0; link = tags[i]; i++) {
			var rel = link.getAttribute('rel');
			if (rel && rel.indexOf('style') != -1) {
				index++;
				if (link.getAttribute('title') == title)
					break;
			}
		}
		return index;
	},
	
	addRule: function(selector, property, sheetIndex, ruleIndex) {
	    if (sheetIndex == undefined) sheetIndex = this.getIndex();
	    var sheet = document.styleSheets[sheetIndex];
	    if (!sheet) return null;

	    ruleIndex = null;
		if (sheet.addRule) { // IE
			if (ruleIndex == undefined) ruleIndex = sheet.rules.length;
			sheet.addRule(selector, '{' + property + '}', ruleIndex );
		} else if (sheet.insertRule) {
			if (ruleIndex == undefined) ruleIndex = sheet.cssRules.length;
			ruleIndex = sheet.insertRule(selector + '{' + property + '}', ruleIndex );
	    }
		return ruleIndex;
	},
	removeRule: function(ruleIndex, sheetIndex) {
		if (sheetIndex == undefined) sheetIndex = this.getIndex();
	    var sheet = document.styleSheets[sheetIndex];
	    if (sheet) {
	    	if (sheet.removeRule) { // IE
	    		sheet.removeRule(ruleIndex);
	    	} else if (sheet.deleteRule) {
	    		sheet.deleteRule(ruleIndex);
	    	}
	    }
	}
}

function UserAgent(userAgent) {
	var ua = userAgent ? userAgent : navigator.userAgent;
	var browsers = {
		IE: 'MSIE ',
		Firefox: 'Firefox/',
		Safari: 'Safari/',
		Opera: 'Opera[/ ]',
		Mozilla: 'Mozilla/',
		Netscape: 'Netscape[0-9]?/'
	};
	for (var name in browsers) {
		this[name] = ua.match(browsers[name] + '(\\d+\.\\d+)') ? parseFloat(RegExp.$1) : 0;
	}
	this.iPhone = ua.indexOf('iPhone') != -1 || ua.indexOf('iPod') != -1;  
}

function create_element(tagName, properties) {
	var element = document.createElement(tagName);
	return Object.extend(element, properties);
}

function select_element(l){
	var list = new Array;
	for(i=0;i<l.length;i++){
		if(l[i].nodeType == 1){
			list.push(l[i]);
		}
	}
	return list;
}

function stopEventPropagation(e) {
	if (e = e || window.event) {
		e.cancelBubble = true;
		e.returnValue = false;
		if (e.stopPropagation) e.stopPropagation();
		if (e.preventDefault) e.preventDefault();
	}
	return false;
}
