/*

DOM.js
======

Defines the basic functions used by the Grammatica website to make 
its web pages interactive.

Functions
---------

DOM.js defines these functions.

hasClass(element, className) -> true or false    
addClass(element, className)
removeClass(element, classes)

hasTagName(element, tagName) -> true or false

e = elements({element | parent, tag, class | Class | className | classes})
    Returns an object which can find particular elements on the page.

e.each(function(x) {...})
    Runs a function over all the elements represented by e.

onLoad(function() {...})
    Sets the function to execute after the page has loaded.

*/

function hasClass(element, classes) {
    if (!classes || classes.length == 0) {
        return true;
    }
    if (!element.className) {
        return false;
    }
    if (typeof classes == 'string') {
        classes = [classes];
    }
    for (var i = 0; i < classes.length; i++) {
        var cn = classes[i];
        var classPattern = new RegExp('\\b' + cn + '\\b');
        if(!element.className.match(classPattern)) {
            return false;
        }
    }
    return true;
}
    
function addClass(element, className) {
    if (!hasClass(element, className)) {
        if (element.className) {
            element.className = element.className + ' ' + className;
        }
        else {
            element.className = className;   
        }
    }
}
    
function removeClass(element, className) {
    if (element.className) {
        var classPattern = new RegExp(' ?\\b' + className + '\\b');
        element.className = element.className.replace(classPattern, '');
    }
}

function hasTagName(element, tagName) {
    if (!element.tagName) {
        return false;
    }
    if (tagName == '*') {
        return true;
    }
    return (element.tagName.toLowerCase() == tagName.toLowerCase());
}

function __Elements(args) {

    this.element = args.element || document;
    if (typeof this.element == 'string') {
        this.element = document.getElementById(this.element);
    }
    
    this.parent = args.parent || null;
    if (typeof this.parent == 'string') {
        this.parent = document.getElementById(this.parent);
    }
    
    this.tag = args.tag || '*'
    
    if (args['class']) {
        this.classes = [args['class']];
    }
    else if (args.Class) {
        this.classes = [args.Class];
    }
    else if (args.className) {
        this.classes = [args.className];
    }
    else {
        this.classes = args.classes || [];
    }
}

__Elements.prototype.each = function(f, obj) {
    if (this.parent) {
        var children = this.parent.childNodes;
        for (var i = 0; i < children.length; i++) {
            var e = children[i];
            if (hasTagName(e, this.tag) && hasClass(e, this.classes)) {
                f.call(obj, e);
            }
        }
    }
    else {
        var elements = this.element.getElementsByTagName(this.tag);
        for (var i = 0; i < elements.length; i++) {
            var e = elements[i];
            if (hasClass(e, this.classes)) {
                f.call(obj, e);
            }
        }
    }
}

function elements(args) {  return new __Elements(args)  };

function onLoad(f) {
    var oldWindowOnLoad = window.onload;
    window.onload = function () {
        if (oldWindowOnLoad) {
            oldWindowOnLoad();
        }
        f();
    }
}