var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}



function findParents(el, tag, cls) {
    var result = [];
    while (el.parentNode && el.tagName) {
        el = el.parentNode;
        if (el.tagName && (!tag || el.tagName.toLowerCase() == tag.toLowerCase()) && (!cls || hasClass(el, cls))) {
            result.push(el); 
        }
    }
    return result;
}

function findChildren(el, tag, cls, id) {
    var result = [];
    //alert(tag+'#'+id+'.'+cls);    
    if (el.childNodes) {
        for(var i=0; i<el.childNodes.length; i++) {
            var child = el.childNodes[i];
            if (
                    child.tagName && 
                    (!tag || tag == '' || child.tagName.toLowerCase() == tag.toLowerCase()) && 
                    (!cls || cls == '' || hasClass(child, cls)) && 
                    (!id || id == '' || child.id == id)) {
                result.push(el.childNodes[i]);
            }
            result = result.concat(findChildren(child, tag, cls, id));
        }
    }
  
    return result;
}


function findNextSiblings(el, tag, cls, id) {
    var result = [];
    while (el.nextSibling) {
        el = el.nextSibling;
        if (
                el.tagName && 
                (!tag || tag == '' || el.tagName.toLowerCase() == tag.toLowerCase()) && 
                (!cls || cls == '' || hasClass(el, cls)) && 
                (!id || id == '' || child.id == id)) {
            result.push(el);
        }
    }
    return result;
}
function findPrevSiblings(el, tag, cls, id) {
    var result = [];
    while (el.previousSibling) {
        el = el.previousSibling;
        if (
                el.tagName && 
                (!tag || tag == '' || el.tagName.toLowerCase() == tag.toLowerCase()) && 
                (!cls || cls == '' || hasClass(el, cls)) && 
                (!id || id == '' || child.id == id)) {
            result.push(el);
        }
    }
    return result;
}



function select(elements, expr) {
    var result = [];
    if (elements.constructor != Array) {
        elements = [elements];
    }
    //first split using separator;
    var expr = expr.split(/\s*,\s*/);
    for (var i=0; i < expr.length;i++) {
        var expr1 = expr[i];
        // split using whitepace
        var expr1 = expr1.split(/\s+/);        
        for (var j=0; j< expr1.length;j++) {
            var children = [];
            var expr2 = expr1[j];
            if (expr2.match(/^(\w+|\*|)((#)(\w+))?((\.)(\w+))?$/)) {
                var tag = RegExp.$1;
                if (tag == '*') {
                    tag = null;
                }
                var id = RegExp.$4;
                var cls = RegExp.$7;
                for(var k=0; k<elements.length;k++) {
                    children = children.concat(findChildren(elements[k], tag, cls, id));
                }
            }
            elements = children;
        }
        result = result.concat(children);
    }
    return result;
}

function hasClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i]== cls) {
            return true;
        }
    }
    return false;
}

function addClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i]== cls) {
            return;
        }
    }
    clss.push(cls);
    el.className = clss.join(' ');
}

function removeClass(el, cls) {
    clss = el.className.split(' ');
    for(var i = 0; i<clss.length;i++) {
        if (clss[i]== cls) {
            clss[i] = null;
            delete clss[i];
        }
    }
    el.className = clss.join(' ');
}

Array.prototype.first = function () {
    return (this.length > 0) ? this[0] : null;
}

Array.prototype.last = function () {
    return (this.length > 0) ? this[this.length-1]:null;
}

Array.prototype.each = function (f) {
    for(var i = 0; i < this.length; i++) {
        f(this[i]);
    }
}

Array.prototype.reduce = function () {
    return this.length > 1 ? this : this[0];
}

var $A = function(iterable) {
    if (iterable == null) {
        return [];
    } else if (iterable.toArray) {
        return iterable.toArray();
    } else if (iterable.constructor == Array) {
        return iterable;
    } else if (typeof iterable == 'object' && iterable.length) {
        var results = [];
        for (var i = 0; i < iterable.length; i++) {
            results.push(iterable[i]);
        }
        return results;
    } else {
        return [iterable];
    }
}

function $() {
    elements=[];  
    for (var i = 0; i < arguments.length; i++) {
        element = arguments[i];
        if (element.constructor == Array) {
            elements = elements.concat($.apply(this, element));
        } else {
            if (typeof element == 'string') {
                element = document.getElementById(element);
            }
            elements.push(element);
        }
    }
    //reduce
    return elements.reduce();
}

function addLoadEvent (f) {
    var o = window.onload;
		
    if (typeof window.onload != 'function') {
        window.onload = f;
    } else {
        window.onload = function() {
            o();
            f();
        }
    }
}
