/*
Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
of Simon Willison (see comments by Simon below).

License:
This file is entirely BSD licensed.
More information:
http://bennolan.com/behaviour/        
*/   

var Behaviour = {
    list : [],
  
    register : function (sheet) {
        Behaviour.list.push(sheet);
    },
  
    start : function () {
        Behaviour.addLoadEvent( function () {
            Behaviour.apply();
        });
    },
    
    apply : function () {
        var h;
        var sheet;
        
        for (h = 0; (sheet = Behaviour.list[h]); h++) {
            Behaviour.applySheet( sheet );
        }
    },

    applySheet : function ( sheet ) {
        var selector;
        var list;
        var element;
        var i;
        
        for (selector in sheet) {
            list = document.getElementsBySelector(selector);
            
            if ( !list ) {
                continue;
            }

            for (i = 0; ( element = list[i] ); i++) {
                sheet[selector](element);
            }
        }
    },
    
    addLoadEvent : function (func) {
        var oldonload = window.onload;
        
        if (typeof window.onload !== 'function') {
            window.onload = func;
        } else {
            window.onload = function () {
                oldonload();
                func();
            };
        }
    }
};

Behaviour.start();

/*
The following code is Copyright (C) Simon Willison 2004.

document.getElementsBySelector(selector)
- returns an array of element objects from the current document
matching the CSS selector. Selectors can contain element names, 
class names and ids and can be nested. For example:

elements = document.getElementsBySelect('div#main p a.external')

Will return an array of all 'a' elements with 'external' in their 
class attribute that are contained inside 'p' elements that are 
contained inside the 'div' element which has id="main"

New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
See http://www.w3.org/TR/css3-selectors/#attribute-selectors

Version 0.4 - Simon Willison, March 25th 2003
-- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
-- Opera 7 fails 
*/

function getAllChildren(e) {
    // Returns all children of element. Workaround required for IE5/Windows. Ugh.
    return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function (selector) {
    // Attempt to fail gracefully in lesser browsers
    if (!document.getElementsByTagName) {
        return [];
    }
    // Split selector in to tokens
    var tokens = selector.split(' ');
    var token,
        bits,
        id,
        tagName,
        element,
        elements,
        className,
        found,
        foundCount,
        i, j, k, h,
        attrOperator,
        attrName,
        attrValue,
        currentContextIndex,
        match_result;
    var checkFunction; // This function will be used to filter the elements
        
    var currentContext = [document];
    for ( i = 0; i < tokens.length; i++) {
        token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');
        if (token.indexOf('#') > -1) {
            // Token is an ID selector
            bits = token.split('#');
            tagName = bits[0];
            id = bits[1];
            element = document.getElementById(id);
            if (tagName && element.nodeName.toLowerCase() !== tagName) {
                // tag with that ID not found, return false
                return [];
            }
            // Set currentContext to contain just this element
            currentContext = [element];
            continue; // Skip to next token
        }
        if (token.indexOf('.') > -1) {
            // Token contains a class selector
            bits = token.split('.');
            tagName = bits[0];
            className = bits[1];
            if (!tagName) {
                tagName = '*';
            }
            // Get elements matching tag, filter them for class selector
            found = [];
            foundCount = 0;
            for (h = 0; h < currentContext.length; h++) {
                if (tagName === '*') {
                    elements = getAllChildren(currentContext[h]);
                } else {
                    elements = currentContext[h].getElementsByTagName(tagName);
                }
                for (j = 0; j < elements.length; j++) {
                    found[foundCount++] = elements[j];
                }
            }
            currentContext = [];
            currentContextIndex = 0;
            for (k = 0; k < found.length; k++) {
                if (found[k].className && found[k].className.match(new RegExp( '\\b' + className + '\\b' ) ) ) {
                    currentContext[currentContextIndex++] = found[k];
                }
            }
            continue; // Skip to next token
        }
        
        // Code to deal with attribute selectors
        if ( ( match_result = token.match(/ ^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ ) ) ) {
            
            tagName = match_result[1];
            attrName = match_result[2];
            attrOperator = match_result[3];
            attrValue = match_result[4];
            
            if (!tagName) {
                tagName = '*';
            }
            // Grab all of the tagName elements within current context
            found = [];
            foundCount = 0;
            for (h = 0; h < currentContext.length; h++) {
                if (tagName === '*') {
                    elements = getAllChildren(currentContext[h]);
                } else {
                    elements = currentContext[h].getElementsByTagName(tagName);
                }
                for (j = 0; j < elements.length; j++) {
                    found[foundCount++] = elements[j];
                }
            }
            currentContext = [];
            currentContextIndex = 0;
            
            switch (attrOperator) {
            
            case '=': // Equality
                checkFunction = function (e) { 
                    return (e.getAttribute(attrName) === attrValue); 
                };
                break;
            case '~': // Match one of space seperated words 
                checkFunction = function (e) { 
                    return (e.getAttribute(attrName).match(new RegExp( '\\b' + attrValue + '\\b' ) ) ); 
                };
                break;
            case '|': // Match start with value followed by optional hyphen
                checkFunction = function (e) { 
                    return (e.getAttribute(attrName).match(new RegExp( '^' + attrValue + '-?' ) ) ); 
                };
                break;
            case '^': // Match starts with value
                checkFunction = function (e) { 
                    return (e.getAttribute(attrName).indexOf(attrValue) === 0); 
                };
                break;
            case '$': // Match ends with value - fails with "Warning" in Opera 7
                checkFunction = function (e) {
                    return (e.getAttribute(attrName).lastIndexOf(attrValue) === e.getAttribute(attrName).length - attrValue.length); 
                };
                break;
            case '*': // Match ends with value
                checkFunction = function (e) {
                    return (e.getAttribute(attrName).indexOf(attrValue) > -1); 
                };
                break;
            default :
                // Just test for existence of attribute
                checkFunction = function (e) { 
                    return e.getAttribute(attrName); 
                };
            }
            currentContext = [];
            currentContextIndex = 0;
            for ( k = 0; k < found.length; k++ ) {
                if (checkFunction(found[k])) {
                    currentContext[currentContextIndex++] = found[k];
                }
            }
            // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
            continue; // Skip to next token
        }
        
        if (!currentContext[0]) {
            return;
        }
        
        // If we get here, token is JUST an element (not a class or ID selector)
        tagName = token;
        found = [];
        foundCount = 0;
        for ( h = 0; h < currentContext.length; h++) {
            elements = currentContext[h].getElementsByTagName(tagName);
            for ( j = 0; j < elements.length; j++) {
                found[foundCount++] = elements[j];
            }
        }
        currentContext = found;
    }
    return currentContext;
};



