// init util
var util = {};

// get heights / widths / scrolls
util.position = new Class(
{
    // get the height of the window / page
    getHeight: function(isFull)
    {
        // make sure isFull exists
        isFull = (isFull == undefined) ? true : isFull;
        
        // init vars
        var oh = document.documentElement.offsetHeight != undefined ? document.documentElement.offsetHeight : (isFull ? 0 : 10000000);
        var ch = document.body.clientHeight != undefined ? document.body.clientHeight : (isFull ? 0 : 10000000);
        var ih = window.innerHeight != undefined ? window.innerHeight : (isFull ? 0 : 10000000);
        var value = false;
        
        // get the wanted value
        value = isFull && oh >= ch && oh >= ih ? oh : (!isFull && oh <= ch && oh <= ih ? oh : value);
        value = isFull && ch >= oh && ch >= ih ? ch : (!isFull && ch <= oh && ch <= ih ? ch : value);
        value = isFull && ih >= ch && ih >= oh ? ih : (!isFull && ih <= ch && ih <= oh ? ih : value);
        
        // return the value
        return value == 0 ? false : value;
    },
    
    // get the width of the window / page
    getWidth: function(isFull)
    {
        // make sure isFull exists
        isFull = (isFull == undefined) ? true : isFull;
        
        // init vars
        var ow = document.documentElement.offsetWidth != undefined ? document.documentElement.offsetWidth : (isFull ? 0 : 10000000);
        var cw = document.body.clientWidth != undefined ? document.body.clientWidth : (isFull ? 0 : 10000000);
        var iw = window.innerWidth != undefined ? window.innerWidth : (isFull ? 0 : 10000000);
        var value = false;
        
        // get the wanted value
        value = isFull && ow >= cw && ow >= iw ? ow : (!isFull && ow <= cw && ow <= iw ? ow : value);
        value = isFull && cw >= ow && cw >= iw ? cw : (!isFull && cw <= ow && cw <= iw ? cw : value);
        value = isFull && iw >= cw && iw >= ow ? iw : (!isFull && iw <= cw && iw <= ow ? iw : value);
        
        // return the value
        return value == 0 ? false : value;
    },
    
    // get the current scroll pos
    getScrollPos: function()
    {
        // init vars
        var db = document.documentElement.scrollTop != undefined ? document.documentElement.scrollTop : 0;
        var de = document.body.scrollTop != undefined ? document.body.scrollTop : 0;
        
        // return the value
        return db >= de ? db : de;
    },
    
    // get the midpoint of the current window
    getMidPoint: function()
    {
        // init vars
        var h = this.getScrollPos() + Math.floor(this.getHeight(false) / 2);
        var w = Math.floor(this.getWidth(false) / 2);
        
        return {height: h, width: w};
    },
    
    // get the size of the given element
    getElementSize: function(element)
    {
        return {height: element.clientHeight, width: element.clientWidth};
    },
    
    // gets the absolute position of an element
    getAbsPosition: function(element)
    {
        // init vars
        var coords = {x:0, y:0};
        
        // get the coords of the node
        while (element)
        {
            // store the coords
            coords.x += element.offsetLeft;
            coords.y += element.offsetTop;
            
            // move to the parent element
            element = element.offsetParent;
        }
        
        // return the coords
        return coords;
    }
});

// creates a unique id or full unique object
util.unique = new Class(
{
    createUnique: function(length)
    {
        // init vars
        var store = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
        var uid = '';
        
        // create the uid
        for (var i = 0; i < length; i ++)
            uid += store[Math.round(Math.random() * (store.length - 1))];
        
        // return the uid
        return uid;
    },
    
    createUniqueObject: function(parentObject)
    {
        // init vars
        var returnVar = '';
        
        // loop through the uid
        while (returnVar == '')
        {
            // get a uid
            var uid = this.createUnique(16);
            
            // check for existence
            if (typeof(parentObject[uid]) == 'undefined')
                returnVar = uid;
        }
        
        // return returnVar
        return returnVar;
    }
});

// john resig's code for events, repackaged
util.events = new Class(
{
    add: function(node, type, func)
    {
        if (node.attachEvent) 
        { 
            node['e' + type + func] = func; 
            node[type + func] = function() {node['e' + type + func](window.event);};
            node.attachEvent('on' + type, node[type + func]); 
        }
        else 
            node.addEventListener(type, func, false); 
    },
    
    remove: function(node, type, func)
    { 
        if (node.detachEvent)
        { 
            node.detachEvent('on'+type, node[type + func]); 
            node[type + func] = null; 
        }
        else 
            node.removeEventListener(type, func, false); 
    }
});

// used for variation templating
util.template = new Class(
{
    init: function(template, node, data, keepChildren, endFunction)
    {
        // make sure node exists
        if (!node) node = template.parentNode;
        
        // remove the old data from the template
        buffalo.utils.clearWhiteSpace(node);
        var children = node.childNodes;
        var length   = children.length - 1;
        var counter  = 0;
        
        // loop through and remove the old children
        if (!keepChildren)
            for (var i= 0; i < length; i ++)
            {
                // check for the counter
                if (children[0] == template) counter = 1;
                
                // remove the child node
                node.removeChild(children[counter]);
            }
        
        // loop through each row of data
        for (var i = 0; i < data.length; i ++)
        {
            // init vars
            var newNode = template.cloneNode(true);
            buffalo.utils.clearWhiteSpace(newNode);
            var newArray = newNode.getElementsByTagName('*');
            
            // backup plan for trs in IE
            if (newNode.nodeName.toUpperCase() == 'TR')
            {
                // init vars
                var newTBody = document.createElement('tbody');
                var newTable = document.createElement('table');
                var newDiv   = document.createElement('div');
                
                // build the node tree
                newDiv.appendChild(newTable);
                newTable.appendChild(newTBody);
                newTBody.appendChild(newNode);
                
                // store the data for manipulation
                var tempData = newDiv.innerHTML;
                
                // loop through and add the new keys
                for (key in data[i])
                    tempData = tempData.replace(new RegExp("\\%"+key.toUpperCase()+"\\%", "gi"), data[i][key]);
                
                // reassign the data
                newDiv.innerHTML = tempData;
                
                // rebuild the newNode
                newNode = newDiv.firstChild.firstChild.firstChild;
            }
            else
                for (key in data[i])
                    newNode.innerHTML = newNode.innerHTML.replace(new RegExp("\\%"+key.toUpperCase()+"\\%", "gi"), data[i][key]);
            
            // add to the main node
            if (!endFunction)
                node.appendChild(newNode.firstChild);
            else
                endFunction(node, newNode, template);
        }
    }
});

// add a capitalise function to string
String.prototype.capitalise = function()
{
    return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase();
}

// set up class
function Class(methods)
{
    // create the new function
    var tempFunction = function() {};
    tempFunction.prototype = methods;
    
    // store all useful options
    tempFunction.prototype.storeOptions = function(options, isSuper)
    {
        for (key in options)
            if (typeof(this[key]) == 'undefined' || isSuper)
                this[key] = options[key];
    };
    
    // return the new function
    return tempFunction;
}

// set up class
function Extends(oldClass, methods)
{
    // create the new function
    var tempFunction = function() {};
    tempFunction.prototype.parent = {};
    tempFunction.prototype.parent.child = tempFunction.prototype;

    // loop through and add the old methods
    for (name in oldClass) 
    {
        // store the method for later user
        tempFunction.prototype[name] = oldClass[name];
        
        // create the new method
        eval('var temp = ' + oldClass[name].toString().replace(/this\./g, "this.child.").replace(/this\;/g, "this.child;"));
        
        // store the new parent method
        tempFunction.prototype.parent[name] = temp;
    }
    
    // loop through and add the new methods
    for (name in methods) tempFunction.prototype[name] = methods[name];
    
    // return the new function
    return tempFunction;
}