
var addListener = function (obj, evt, fn, scope) {
    var tfn = function (e) { fn.call(scope, e); };
	if(obj.addEventListener) {
	  obj.addEventListener(evt, tfn, false);
	} else {
	  obj.attachEvent("on"+evt, tfn);
	}
};
var getTarget = function(ev) {
	var t = ev.target || ev.srcElement;
	return resolveTextNode(t);
};
var resolveTextNode = function(n) {
	try {
		if (n && 3 == n.nodeType) { return n.parentNode; }
	} catch(e) { }
	return n;
};

var stopEvent = function(ev) {
	stopPropagation(ev);
	preventDefault(ev);
};
var stopPropagation = function(ev) {
	if (ev.stopPropagation) {
		ev.stopPropagation();
	} else {
		ev.cancelBubble = true;
	}
};

var preventDefault = function(ev) {
	if (ev.preventDefault) {
		ev.preventDefault();
	} else {
		ev.returnValue = false;
	}
};
			
var toggleClass = function (el, cn) {
	if(el.className.indexOf(cn) >= 0) {
		el.className=el.className.replace(cn, '');
		return false;
	} else {
		el.className+= ' ' + cn;
		return true;
	}
};
var addClass = function (el, cn) {
	if(el.className.indexOf(cn) < 0) {
		el.className += ' ' + cn;
		return true;
	} else {
		return false;
	}
};
var removeClass = function (el, cn) {
	if(el.className.indexOf(cn) >= 0) {
		el.className=el.className.replace(cn, '');
		return true;
	} else { 	
		return false;
	}
};
var hasClass = function (el, cn) {
	if(el.className.indexOf(cn) >= 0) {
		return true
	} else {
		return false;
	}
};

var ElementHandler = function () {
	this.elements = [];
	this.handlers = {};

	this.addElement = function (el) { 
		this.elements.push(new Element(el, this));
	};

	this.addHandler = function (evt, tag, cls, handler) {
		if (!this.handlers[evt]) { this.handlers[evt] = {}; }
		if (!this.handlers[evt][tag]) { this.handlers[evt][tag] = {}; }
		if (!this.handlers[evt][tag][cls]) { this.handlers[evt][tag][cls] = handler; }
	};

	this.invokeHandler = function (evt, el) {
		if( 
			evt
			&& this.handlers[evt] 
			&& this.handlers[evt][el.tagName]
		)
		{
			var classes = this.handlers[evt][el.tagName];
			for (var i in classes) {
				if( hasClass(el, i) ) {
					if (!this.handlers[evt][el.tagName][i].call(this, el)) { return false; }
				}
			}
		}
		return true;
	};

};

var Element = function (el, h) {
	this.element = el;
	this.handler = h;
	this.click = function(e) {
		var el = getTarget(e);
		do {
			if(!this.handler.invokeHandler("click", el)) { 
				stopEvent(e);
				break;
			}
			el = el.parentNode;
		} while (el != this.element.parentNode);
	};

	this.mouseover = function(e) {
		var el = getTarget(e);
		do {
			if(!this.handler.invokeHandler("mouseover", el)) { 
				stopEvent(e);
				break;
			}
			el = el.parentNode;
		} while (el != this.element.parentNode);
	};

	this.mouseout = function(e) {
		var el = getTarget(e);
		do {
			if(!this.handler.invokeHandler("mouseout", el)) { 
				stopEvent(e);
				break;
			}
			el = el.parentNode;
		} while (el != this.element.parentNode);
	};
	
	addListener(el, 'click', this.click, this, true);
	addListener(el, 'mouseover', this.mouseover, this, true);
	addListener(el, 'mouseout', this.mouseout, this, true);
  
};

var Panel = function (p, o) {
 var _p = document.getElementById(p);
 var _o = document.getElementById(o);
 return {panel: _p, opener: _o};
};

var PanelHandler = function (c) {
	var _openPanels = [];
	var _openClasses = c || {panel: "PanelOpen", opener: "OpenerOpen"} ;
	this.panelClick = function (el) {
		closePanelsExcept(el);
		return false;
	};
	this.lazycloserClick = function (el) {
		closePanelsExcept(false);
		return true;
	};
	this.closerClick = function (el) {
		closePanelsExcept(false);
		return false;
	};
	this.openerClick = function (el) {	
		closePanelsExcept(el);
		return false;	
	};
	this.addPanel = function (p) {
		_openPanels.push(p);
	};
	var closePanelsExcept = function(el) {
		for(var i=0; i<_openPanels.length; i++) {
			if (_openPanels[i].panel == el || _openPanels[i].opener == el) {
				addClass(_openPanels[i].panel,_openClasses.panel); 
				addClass(_openPanels[i].opener,_openClasses.opener); 
				el = false;
			} else {
				removeClass(_openPanels[i].panel,_openClasses.panel);
				removeClass(_openPanels[i].opener,_openClasses.opener); 
			}
		}
	};
};
