// Namespace to place our HTMLElement methods in
function MEC() {}
var ME = new MEC();
MEC.prototype.$hasInit = 1;
// Add/remove event handler tofrom element
MEC.prototype.$event = function (et, cb, c) { var o = this; c = c || false; if (o == document && !document.all) { o = window; } if (o.addEventListener) { o.addEventListener(et, cb, c); } else if (o.attachEvent) { o.attachEvent("on" + et, cb); } };
MEC.prototype.$revent = function (et, cb, c) { var o = this; c = c || false; if (o == document && !document.all) { o = window; } if (o.removeEventListener) { o.removeEventListener(et, cb, c); } else if (o.detachEvent) { o.detachEvent("on" + et, cb); } };
// Show/hide object
MEC.prototype.$show = function () { this.style.display = ""; };
MEC.prototype.$hide = function () { this.style.display = "none"; };
// Add/remove classes to/from element
MEC.prototype.$cadd = function (c) { if (this.className.indexOf(c) == -1) { this.className = this.className + " " + c; return 1; } return 0; };
MEC.prototype.$crem = function (c) { var p = this.className.indexOf(c); if (p != -1) { p != 0 ? p-- : p; this.className = this.className.substr(0, p) + " " + this.className.substr(p + c.length + 1); return 1; } return 0; };
// Get computed style of an element
MEC.prototype.$cstyle = function (css) {
  var value = false;
  if (document.defaultView && document.defaultView.getComputedStyle) { value = document.defaultView.getComputedStyle(this, '').getPropertyValue( css.replace( /[A-Z]/g, function( match, c ) { return "-" + match.toLowerCase(); } ) ); }
  else if ( this.currentStyle ) { value = this.currentStyle[ css ]; }
  return value;
};
// Move to parent element until we find parent with given tag
MEC.prototype.$parentToSelector = function(tag) { tag = tag.toUpperCase(); var e = this.parentNode; while (e && e.tagName && e.tagName.toUpperCase() != tag) { e = e.parentNode; } return e; };
// Move to sibling element until we find sibling with given tag
MEC.prototype.$siblingToSelector = function(tag) { tag = tag.toUpperCase(); var e = this.nextSibling; while (e && (!e.tagName || e.tagName.toUpperCase() != tag)) { e = e.nextSibling; } return e; };

// Hide ref to HTMLElement object by only storing Id
function HEWrap(e) { this.Id = $id(e); }
HEWrap.prototype.$deref = function () { return $(this.Id); };

// General helper functions
function $(e) { return typeof(e) == 'string' ? document.getElementById(e) : e; }
function $id(e) { e = $(e); return e.id ? e.id : (e.id = $newid()); }
function $wraphe(e) { if (e.tagName) { return new HEWrap(e); } return e; }
function $unwraphe(e) { if (e instanceof HEWrap) { return e.$deref(); } return e; }
function $max(a, b) { return a > b ? a : b; }
function $def(a) { return typeof a != 'undefined'; }
function $list2arr(a) { var r = []; var l = a.length; for (var i = 0; i < l; i++) { r[i] = a[i]; } return r; }
// Returns closure that calls method 'm' on object 'o' with any other args as args to method call
function $callmethod(m /*, o, a1, ... */) { var a = $list2arr(arguments).$sublist(1).$map($wraphe); return function () { var c = a.$map($unwraphe); var o = c.shift(); return m.apply(o, c) }; }
// As above, but first param in method call is the event object
function $callevent(m /*, o, a1, ... */) { var a = $list2arr(arguments).$sublist(1).$map($wraphe); return function (e) { var c = a.$map($unwraphe); var o = c.shift(); c = [ e ? e : window.event ].concat(c); return m.apply(o, c); }; }
// Attach MEC methods to HTMLElement
function $me(Obj) { Obj = $(Obj); if (!Obj || !Obj.tagName) { return Obj; } if (Obj.$hasInit) { return Obj; } for (var M in MEC.prototype) { Obj[M] = MEC.prototype[M]; } return Obj; }
function $bySelector(tag) { var Col = document.getElementsByTagName(tag); var r = []; var l = Col.length; for (var i = 0; i < l; i++) { r[i] = Col[i]; } return r; }
$newid = function() { var IdCounter = 1; return function() { return "GeneratedId" + IdCounter++; } }();

// Add push/pop to array if IE5
if (!$def(Array.prototype.push)) { Array.prototype.push = function (e) { this[this.length] = e; } }
if (!$def(Array.prototype.pop)) { Array.prototype.pop = function () { if (this.length == 0) { return ''; } var e = this[this.length-1]; this.length --; return e; } }
if (!$def(Array.prototype.shift)) { Array.prototype.shift = function () { if (this.length == 0) { return ''; } var e = this[0]; for (var i = 1; i < this.length; i++) { this[i-1] = this[i]; } this.length --; return e; } }

Array.prototype.$for = function (f) { var l = this.length; for (var i = 0; i < l; i++) { f(this[i]); } };
Array.prototype.$map = function (f) { var r = []; var l = this.length; for (var i = 0; i < l; i++) { r[i] = f(this[i]); } return r; };
Array.prototype.$reduce = function(f) { var r; var l = this.length; for (var i = 0; i < l; i++) { r = f(r, this[i]); } return r; };
Array.prototype.$each = function (f) { var l = this.length; for (var i = 0; i < l; i++) { f(this[i]); }; return this; };
Array.prototype.$clone = function() { return this.concat(); };
Array.prototype.$sublist = function(f, l) { var r = []; if (f>l) { return r; } if (!$def(l)) { l = this.length-1 }; for (var i = f, j = 0; i <= l; i++, j++) { r[j] = this[i]; } return r; };

if (navigator) {
  document.meIsIE = navigator.userAgent.indexOf('MSIE') != -1 ? 1 : 0;
  document.meIsMoz = navigator.userAgent.indexOf('Gecko/') != -1 ? 1 : 0;
  document.meIsOpera = navigator.userAgent.indexOf('Opera') != -1 ? 1 : 0;
  document.meIsKonq = navigator.userAgent.indexOf('KHTML') != -1 ? 1 : 0;
}

