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

Array.prototype.select = function(predicate) {
    var result = [];
    for (var i=0;i<this.length;i++) {
        if (predicate(this[i])) {
            result.push(this[i]);
        }
    }
    
    return result;
}

Array.prototype.hasAny = function(predicate) {
    var result = false;
    
    for (var i=0;i<this.length;i++) {
        if (predicate(this[i])) {
            result = true;
            break;
        }
    }
    
    return result;
}

Array.prototype.getFirstMatchingIndex = function(predicate) {
    var result = null;
    
    for (var i=0;i<this.length;i++) {
        if (predicate(this[i])) {
            result = i;
            break;
        }
    }    
    
    return result;
}

Array.prototype.contains = function(element) {
    var result = false;
    
    for (var i=0;i<this.length;i++) {
        if (this[i] === element) {
            result = true;
            break;
        }
    }
    
    return result;
}

Array._propertyIsEnumerable = Array.prototype.propertyIsEnumerable;

Array._extensions = ['forEach', 'select', 'hasAny', 'getFirstMatchingIndex', 'contains'];

Array.prototype.propertyIsEnumerable = function(propertyName) {
    var result;
    
    if (Array._extensions.contains(propertyName)) {
        result = false;
    } else {
        result = Array._propertyIsEnumerable.call(this, propertyName);
    }
    
    return result;
}


Iterator = function() {    
}

Iterator.prototype.hasNext = function() {return false;}
Iterator.prototype.next = function() { return undefined; }

Iterator.prototype.forEach = function(method) {
    while (this.hasNext()) {
        method(this.next());
    }
}

Iterator.prototype.first = function() {
    var first;

    this.rewind();
    
    if (this.hasNext()) {
        first = this.next();        
    }
    
    this.rewind();
    
    return first;
}

Iterator.prototype.select = function(predicate) {
    this.rewind();
    return new SelectIterator(this, predicate);
}

Iterator.prototype.map = function(mapFunction) {
    this.rewind();
    return new MapIterator(this, mapFunction);    
}

Iterator.prototype.rewind = function() {}


Iterator.prototype.toArray = function() {
    var result = [];
    while (this.hasNext()) {
        result.push(this.next());
    }    
    
    return result;
}

ArrayIterator = function(items) {
    this.items = items;
    this.index = 0;
    this.lastIndex = this.items.length - 1;
}

YAHOO.lang.extend(ArrayIterator, Iterator);

ArrayIterator.prototype.hasNext = function() {
    return this.index <= this.lastIndex;
}

ArrayIterator.prototype.next = function() {
    return this.items[this.index++];
}

ArrayIterator.prototype.rewind = function() {
    this.index = 0;
}

ArrayIterator.prototype.hasAny = function(predicate) {
    var result = false;
    this.rewind();
    
    while (this.hasNext()) {
        if (predicate(this.next())) {
            result = true;
            break;
        }
    }    
    
    this.rewind();
    
    return result;
}



SelectIterator = function(iterator, predicate) {
    this.iterator = iterator;
    this.predicate = predicate;
    this.current = undefined;
}
YAHOO.lang.extend(SelectIterator, Iterator);

SelectIterator.prototype.rewind = function() {
    this.iterator.rewind();
}

SelectIterator.prototype._moveToNext = function() {
    var result = false;
    
    while (this.iterator.hasNext()) {
        var item = this.iterator.next();    
        if (this.predicate(item)) {
            this.current = item;
            result = true;
            break;
        }
    }    
    
    return result && this.current !== undefined;
}

SelectIterator.prototype.hasNext = function() {
    return (this.current !== undefined)  || this._moveToNext();    
}

SelectIterator.prototype.next = function() {
    var result;
    
    if (this.current === undefined) {
        this._moveToNext();
    }
    result = this.current;
    this.current = undefined;    
    
    return result;
}

MapIterator = function(iterator, mapFunction){
    this.iterator = iterator;
    this.mapFunction = mapFunction;
}

YAHOO.lang.extend(MapIterator, Iterator);

MapIterator.hasNext = function() {
    return this.iterator.hasNext();
}

MapIterator.next = function() {
    return this.mapFunction(this.iterator.next());
}

MapIterator.rewind = function() {
    this.iterator.rewind();
}



Elements = {};

Elements.Methods = ['clear', 'setValue', 'remove', 'getChildrenByClassName'];

Elements.clear = function(element) {
    var child = element.firstChild;
    while (child) {
        element.removeChild(child);
        child = child.nextSibling;
    }
}

Elements.setValue = function(element, value) {
    Elements.clear(element);
    
    element.appendChild(
        document.createTextNode(value)
    );
}

Elements.remove = function(element) {
    element.parentNode.removeChild(element);
}

Elements.getChildrenByClassName = function(element, className) {
    var elements = [];
    
    Elements._addChildrenByClassName(element, className, elements);
    
    return elements;    
}

Elements._addChildrenByClassName = function(element, className, target) {
    var node = element.firstChild;
    while (node != null) {
        if (node.nodeType == 1) {
            if (node.className == className) {
                target.push(node);
            }
            Elements._addChildrenByClassName(node, className, target);
        }
        node = node.nextSibling;
    }
}

function E(element) {
    if (typeof(element) == 'string') {
        element = $(element);
    }
    
    if (!element._enhanced) {
        Elements.Methods.forEach(
            function(method) {
                element[method] = function() {
                    var targetArguments = [element];
                    for (var i=0;i<arguments.length;i++) {
                        targetArguments.push(arguments[i]);
                    }
                    
                    return Elements[method].apply(this, targetArguments);
                }
            }
        );
        element._enhanced = true;
    }
    
    return element;
}

function I(collection) {
    var iterator;
    
    if (collection && collection.length) {
        iterator = new ArrayIterator(collection);
    } else {
        iterator = new ArrayIterator([]);
    } 
    
    return iterator;    
}

if (!Function.prototype.bind) {
    Function.prototype.bind = function(target, args) {
        var _function = this;
        if (!args) {
            args = [];
        }
        
        var wrapper = function() {
            return _function.apply(target, args.concat(I(arguments).toArray()));
        }
        
        return wrapper;
    }
}

String.PAD_LEFT = 'left';
String.PAD_RIGHT = 'right';

String.prototype.pad = function(length, character, where) {
    if (character === undefined) {
        character = ' ';
    }
    
    var paddingLength = length - this.length;
    
    var result = this;
    
    switch(where) {
        case String.PAD_LEFT:
            for (var i=0;i<paddingLength;i++) {
                result = character + result;
            }
            break;
        case String.PAD_RIGHT:
        default:
            for (var i=0;i<paddingLength;i++) {
                result += character;
            }
        
    }
    
    return result;
    
}