/**
 * Jax JavaScript Library v0.9 Alpha
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.TXT.
 * It is also available through the world-wide-web at this URL:
 * http://jax.moc10media.com/LICENSE.TXT
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to info@moc10media.com so we can send you a copy immediately.
 *
 * Nick Sagona, III <nick@moc10media.com>
 * Copyright (c) 2009 Moc 10 Media, a division of The Working Man Group, LLC. (http://www.moc10media.com)
 *
 */


/**
 *
 * Jax Browser Component
 *
 */

// Prototype for the JaxBrowser object and its methods and properties.
function JaxBrowser() {

    // Define Browser properties.
    this.ua = navigator.userAgent;
    this.platform = null;
    this.os = null;
    this.browser = null;
    this.version = null;

    // Determine system platform and OS version.
    if (this.ua.indexOf('Windows') != -1) {
        this.platform = 'Windows';
        this.os = (this.ua.indexOf('Windows NT') != -1) ? this.ua.substring(this.ua.indexOf('Windows NT'), this.ua.indexOf('Windows NT') + 14) : 'Windows';
    } else if (this.ua.indexOf('Macintosh') != -1) {
        this.platform = 'Macintosh';
        if (this.ua.indexOf('Intel') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('Intel'));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else if (this.ua.indexOf('PPC') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('PPC'));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'Macintosh';
        }
    } else if (this.ua.indexOf('Linux') != -1) {
        this.platform = 'Linux';
        if (this.ua.indexOf('Linux ') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('Linux '));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'Linux';
        }
    } else if (this.ua.indexOf('SunOS') != -1) {
        this.platform = 'SunOS';
        if (this.ua.indexOf('SunOS ') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('SunOS '));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'SunOS';
        }
    } else if (this.ua.indexOf('OpenBSD') != -1) {
        this.platform = 'OpenBSD';
        if (this.ua.indexOf('OpenBSD ') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('OpenBSD '));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'OpenBSD';
        }
    } else if (this.ua.indexOf('NetBSD') != -1) {
        this.platform = 'NetBSD';
        if (this.ua.indexOf('NetBSD ') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('NetBSD '));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'NetBSD';
        }
    } else if (this.ua.indexOf('FreeBSD') != -1) {
        this.platform = 'FreeBSD';
        if (this.ua.indexOf('FreeBSD ') != -1) {
            this.os = this.ua.substring(this.ua.indexOf('FreeBSD '));
            this.os = this.os.substring(0, this.os.indexOf(';'));
        } else {
            this.os = 'FreeBSD';
        }
    }

    // Determine browser and browser version.
    if (this.ua.indexOf('Camino') != -1) {
        this.browser = 'Camino';
        this.version = this.ua.substring(this.ua.indexOf('Camino/') + 7);
    } else if (this.ua.indexOf('Chrome') != -1) {
        this.browser = 'Chrome';
        this.version = this.ua.substring(this.ua.indexOf('Chrome/') + 7);
        this.version = this.version.substring(0, this.version.indexOf(' '));
    } else if (this.ua.indexOf('Firefox') != -1) {
        this.browser = 'Firefox';
        this.version = this.ua.substring(this.ua.indexOf('Firefox/') + 8);
    } else if (this.ua.indexOf('MSIE') != -1) {
        this.browser = 'MSIE';
        this.version = this.ua.substring(this.ua.indexOf('MSIE ') + 5, this.ua.indexOf('MSIE ') + 8);
    } else if (this.ua.indexOf('Konqueror') != -1) {
        this.browser = 'Konqueror';
        this.version = this.ua.substring(this.ua.indexOf('Konqueror/') + 10);
        this.version = this.version.substring(0, this.version.indexOf(';'));
    } else if (this.ua.indexOf('Navigator') != -1) {
        this.browser = 'Navigator';
        this.version = this.ua.substring(this.ua.indexOf('Navigator/') + 10);
    } else if (this.ua.indexOf('Opera') != -1) {
        this.browser = 'Opera';
        this.version = this.ua.substring(this.ua.indexOf('Opera/') + 6);
        this.version = this.version.substring(0, this.version.indexOf(' '));
    } else if (this.ua.indexOf('Safari') != -1) {
        this.browser = 'Safari';
        this.version = this.ua.substring(this.ua.indexOf('Version/') + 8);
        this.version = this.version.substring(0, this.version.indexOf(' '));
    }

}


/**
 *
 * Jax Cookie Component
 *
 */

// Function to set a cookie.
function setCookie(name, value, expire) {

    // Create expiration date.
    var exdate = new Date();
    exdate.setDate(exdate.getDate() + expire);

    // Set the cookie with or without an expiration date, based on the parameter passed.
    document.cookie = name + '=' + escape(value) + ((expire == null) ? '' : ';expires=' + exdate.toGMTString());

}

// Function to get a cookie.
function getCookie(name) {

    // If the cookie is set, parse the value.
    if (document.cookie.length > 0) {

        start = document.cookie.indexOf(name + '=');

        if (start != -1) {
            start = start + name.length + 1;
            end = document.cookie.indexOf(';', start);
            if (end == -1) {
                end = document.cookie.length;
            }
            return unescape(document.cookie.substring(start, end));
        } else {
            return '';
        }

    } else {
        // Else, return nothing.
        return '';

    }

}

// Function to delete a cookie.
function delCookie(name) {
    setCookie(name, '', -1);
}

/**
 *
 * JaxElement Component
 *
 */

// Prototype for the JaxElement object and its methods and properties.
function JaxElement(elemType, appendTo, attribs, html) {

    // Set the parent element and create the child element.
    this.parentElem = document.getElementById(appendTo);
    this.elem = document.createElement(elemType);

    // Set any element attributes.
    if (attribs != undefined) {
        for (var i = 0; i < attribs.length; i++) {
            this.elem.setAttribute(attribs[i][0], attribs[i][1]);
        }
    }

    // Set any HTML within the element.
    if (html != undefined) {
        this.elem.innerHTML = html;
    }

    // Append the child element to the parent element.
    this.parentElem.appendChild(this.elem);

    // Method to remove the child element.
    this.remove = function() {
        this.parentElem.removeChild(this.elem);
    }

}

// Prototype for the JaxElementInput object and its methods and properties.
function JaxElementInput(inputType, appendTo, attribs) {

    // Set the parent element and create the child element.
    this.parentElem = document.getElementById(appendTo);
    this.elem = document.createElement('input');
    this.elem.setAttribute('type', inputType);

    // Set any element attributes.
    if (attribs != undefined) {
        for (var i = 0; i < attribs.length; i++) {
            this.elem.setAttribute(attribs[i][0], attribs[i][1]);
        }
    }

    // Append the child element to the parent element.
    this.parentElem.appendChild(this.elem);

    // Method to remove the child element.
    this.remove = function() {
        this.parentElem.removeChild(this.elem);
    }

}



/**
 *
 * Jax Effects Component
 *
 */

// Prototype for the JaxFx object and its methods and properties.
function JaxFx() {

    // Define Fx properties.
    this.count = 0;
    this.tween = null;
    this.speed = null;
    this.steps = new Array();

    // Method to show an element.
    this.show = function(elem) {
        document.getElementById(elem).style.display = 'block';
    }

    // Method to hide an element.
    this.hide = function(elem) {
        document.getElementById(elem).style.display = 'none';
    }

    // Method to move an element, either over time, or instantaneously.
    this.move = function(elem, x, y, twn, spd) {

        // If animation parameters are passed, animate the move.
        if ((twn != null) && (spd != null)) {

            this.elm = elem;
            this.tween = twn;
            this.speed = spd;
            this.calcSteps(x, y, parseInt(document.getElementById(elem).style.left), parseInt(document.getElementById(elem).style.top), this.tween);

            function animateMove(obj, sp) {
                if (obj.count < obj.steps.length) {
                    document.getElementById(obj.elm).style.left = obj.steps[obj.count][0] + 'px';
                    document.getElementById(obj.elm).style.top = obj.steps[obj.count][1] + 'px';
                    obj.count++;
                    o = obj;
                    t = setTimeout(function() { animateMove(o, o.speed) }, o.speed);
                } else {
                    obj.count = 0;
                    obj.elm = null;
                    obj.tween = null;
                    obj.speed = null;
                    obj.steps = new Array();
                    t = clearTimeout(t);
                }
            }

            animateMove(this, this.speed);

        } else {
            // Else, move instantaneously.
            document.getElementById(elem).style.left = x + 'px';
            document.getElementById(elem).style.top = y + 'px';
        }

    }

    // Method to resize an element, either over time, or instantaneously.
    this.resize = function(elem, w, h, twn, spd) {

        // If animation parameters are passed, animate the resize.
        if ((twn != null) && (spd != null)) {

            this.elm = elem;
            this.tween = twn;
            this.speed = spd;
            this.calcSteps(w, h, parseInt(document.getElementById(elem).style.width), parseInt(document.getElementById(elem).style.height), this.tween);

            function animateResize(obj, sp) {
                if (obj.count < obj.steps.length) {
                    document.getElementById(obj.elm).style.width = obj.steps[obj.count][0] + 'px';
                    document.getElementById(obj.elm).style.height = obj.steps[obj.count][1] + 'px';
                    obj.count++;
                    o = obj;
                    t = setTimeout(function() { animateResize(o, o.speed) }, o.speed);
                } else {
                    obj.count = 0;
                    obj.elm = null;
                    obj.tween = null;
                    obj.speed = null;
                    obj.steps = new Array();
                    t = clearTimeout(t);
                }
            }

            animateResize(this, this.speed);

        } else {
            // Else, resize instantaneously.
            document.getElementById(elem).style.width = w + 'px';
            document.getElementById(elem).style.height = h + 'px';
        }

    }

    // Method to fade an element, either over time, or instantaneously.
    this.fade = function(elem, f, twn, spd) {

        brws = new JaxBrowser();
        op = (brws.browser == 'MSIE') ? document.getElementById(elem).style.filter.substring(document.getElementById(elem).style.filter.indexOf('=') + 1, document.getElementById(elem).style.filter.indexOf(')')) : (document.getElementById(elem).style.opacity * 100);

        if (f != 0) {
            document.getElementById(elem).style.display = 'block';
        }

        // If animation parameters are passed, animate the fade.
        if ((twn != null) && (spd != null)) {

            this.elm = elem;
            this.change = f;
            this.tween = twn;
            this.speed = spd;
            this.calcStep(op, f, this.tween);

            function animateFade(obj, sp) {
                if (obj.count < obj.steps.length) {
                    if (brws.browser == 'MSIE') {
                        document.getElementById(obj.elm).style.filter = 'alpha(opacity=' + obj.steps[obj.count] + ')';
                    } else {
                        document.getElementById(obj.elm).style.opacity = obj.steps[obj.count] / 100;
                    }
                    obj.count++;
                    o = obj;
                    t = setTimeout(function() { animateFade(o, o.speed) }, o.speed);
                } else {
                    if (obj.change == 0) {
                        document.getElementById(obj.elm).style.display = 'none';
                    } else {
                        if (brws.browser == 'MSIE') {
                            document.getElementById(obj.elm).style.filter = 'alpha(opacity=' + obj.change + ')';
                        } else {
                            document.getElementById(obj.elm).style.opacity = obj.change / 100;
                        }
                    }
                    obj.count = 0;
                    obj.elm = null;
                    obj.change = null;
                    obj.tween = null;
                    obj.speed = null;
                    obj.steps = new Array();
                    t = clearTimeout(t);
                }
            }

            animateFade(this, this.speed);

        } else {
            // Else, fade instantaneously.
            if (brws.browser == 'MSIE') {
                document.getElementById(elem).style.filter = 'alpha(opacity=' + f + ')';
            } else {
                document.getElementById(elem).style.opacity = f / 100;
            }
            if (f == 0) {
                document.getElementById(elem).style.display = 'none';
            }
        }

    }

    // Method to wipe an element on or off vertically, either over time, or instantaneously.
    this.wipe = function(elem, h, twn, spd) {

        if (h != 0) {
            document.getElementById(elem).style.display = 'block';
        }

        // If animation parameters are passed, animate the wipe.
        if ((twn != null) && (spd != null)) {

            this.elm = elem;
            this.change = h;
            this.tween = twn;
            this.speed = spd;
            this.calcStep(parseInt(document.getElementById(elem).style.height), h, this.tween);

            function animateWipe(obj, sp) {
                if (obj.count < obj.steps.length) {
                    document.getElementById(obj.elm).style.height = obj.steps[obj.count] + 'px';
                    obj.count++;
                    o = obj;
                    t = setTimeout(function() { animateWipe(o, o.speed) }, o.speed);
                } else {
                    if (obj.change == 0) {
                        document.getElementById(obj.elm).style.display = 'none';
                    } else {
                        document.getElementById(obj.elm).style.height = obj.change + 'px';
                    }
                    obj.count = 0;
                    obj.elm = null;
                    obj.change = null;
                    obj.tween = null;
                    obj.speed = null;
                    obj.steps = new Array();
                    t = clearTimeout(t);
                }
            }

            animateWipe(this, this.speed);

        } else {
            // Else, wipe instantaneously.
            document.getElementById(elem).style.height = h + 'px';

            if (h == 0) {
                document.getElementById(elem).style.display = 'none';
            }
        }

    }

    // Method to calculate the animation steps between a 2-dimensional start point and end point, i.e. x1, y2 to x2, y2.
    this.calcSteps = function(a, b, c, d, tween) {

        // Reset the array.
        this.steps = new Array();

        // Calculate any remainders.
        arem = (a - c) % tween;
        brem = (b - d) % tween;

        // Calculate the "distance" of a step of animation.
        astep = (arem != 0) ? ((a - c - arem) / tween) : ((a - c) / tween);
        bstep = (brem != 0) ? ((b - d - brem) / tween) : ((b - d) / tween);

        // Calculate all of the steps of animation, storing in the array.
        for (i = 0; i <= tween; i++) {
            curA = c + (astep * i);
            curB = d + (bstep * i);
            this.steps.push(Array(curA, curB));
        }

        // Compensate for any odd remainders.
        lastA = (arem != 0) ? (curA + arem) : curA;
        lastB = (brem != 0) ? (curB + brem) : curB;
        this.steps.push(Array(lastA, lastB));

    }

    // Method to calculate the animation steps between a 1-dimensional start point and end point, i.e. x1 to x2.
    this.calcStep = function(a, b, tween) {

        // Reset the array.
        this.steps = new Array();

        // Calculate any remainders.
        arem = (a - b) % tween;

        // Calculate the "distance" of a step of animation.
        astep = (arem != 0) ? (Math.abs((a - b - arem) / tween)) : (Math.abs((a - b) / tween));

        // Calculate all of the steps of animation, storing in the array.
        for (i = 0; i <= tween; i++) {
            curA = (b < a) ? (parseInt(a) - (astep * i)) : (parseInt(a) + (astep * i));
            this.steps.push(curA);
        }

        // Compensate for any odd remainders.
        if (arem != 0) {
            lastA = (b < a) ? (curA - arem) : (curA + arem);
        } else {
            lastA = curA;
        }
        this.steps.push(lastA);

    }

}


/**
 *
 * Jax Event Component
 *
 */

// Function to add an event listener to the window or document.
function addEvent(evt, func) {

    // Check the event type and the DOM obj accordingly.
    if ((evt == 'scroll') || (evt == 'resize')) {
        obj = window;
    } else {
        obj = document;
    }

    // Detect browser and add the correct event listener.
    brws = new JaxBrowser();

    if (brws.browser == 'MSIE') {
        obj.attachEvent('on' + evt, func);
    } else {
        obj.addEventListener(evt, func, true);
    }

}


/**
 *
 * Jax Flash Component
 *
 */

// Function to dynamically write out the flash code to work around any browser display issues, i.e., the IE "white box" issue.
function flashMovie(url, nm, wid, hgt, bgcolor, wmode, ver) {

    if (bgcolor == null) {
        bgcolor = '#ffffff';
    }
    if (wmode == null) {
        wmode = 'window';
    }
    if (ver == null) {
        ver = 9;
    }

    document.write('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=' + ver + ',0,0,0" width="' + wid + '" height="' + hgt + '" id="' + nm + '" align="middle">');
    document.write('    <param name="allowScriptAccess" value="sameDomain" />');
    document.write('    <param name="movie" value="' + url + '" />');
    document.write('    <param name="quality" value="high" />');
    document.write('    <param name="bgcolor" value="' + bgcolor + '" />');
    document.write('    <param name="wmode" value="' + wmode + '" />');
    document.write('    <embed src="' + url + '" quality="high" bgcolor="' + bgcolor + '" wmode="' + wmode + '" width="' + wid + '" height="' + hgt + '" name="' + nm + '" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://get.adobe.com/flashplayer/" />');
    document.write('    </embed>');
    document.write('</object>');

}

// Load a variable into a SWF.
function loadFlashVar(nm, tar, val) {

	if (eval('window.' + nm)) {
	    windowName = eval("window.document['" + nm + "']");
	    windowName.SetVariable(tar, val);
	} else if (eval('document.' + nm)) {
	    docName = eval('document.' + nm);
	    docName.SetVariable(tar, val);
	}

}


/**
 *
 * Jax Form Component
 *
 */

// Prototype for the JaxForm object and its methods and properties.
function JaxForm(formId, conds) {

    // Define form properties.
    this.id = formId;
    this.fo = document.getElementById(this.id);
    this.conditions = conds;
    this.validators = new Array();

    if (this.conditions != null) {
        // Loop through the validators array that was passed.
        for (var i = 0; i < this.conditions.length; i++) {
            foElem = eval('this.fo.' + this.conditions[i][0]);
            foElem.setAttribute('jax', this.conditions[i][1]);
        }
    }

    // Method to validate the form.
    this.validate = function() {

        // Clear the validators array.
        this.validators = new Array();

        // Parse through the different types of form elements.
        this.parseFormElements('input');
        this.parseFormElements('select');
        this.parseFormElements('textarea');

        // Loop through the current global validators array.
        for (var i = 0; i < this.validators.length; i++) {

            // Check form element and return error message
            error = this.formElementIsValid(this.validators[i]);

            // If there is an error, display error message, focus the incorrect field and return false.
            if (error != null) {

                alert(error);

                if (this.validators[i][0] == 'radio') {
                    fo = eval('this.fo.' + this.validators[i][1] + '[0]');
                } else if (this.validators[i][0] == 'checkbox') {
                    fo = eval('this.fo.' + this.validators[i][1].substring(0, this.validators[i][1].indexOf('[')));
                } else {
                    fo = eval('this.fo.' + this.validators[i][1]);
                }

                fo.focus();
                if (this.validators[i][0].indexOf('select') == -1) {
                    fo.select();
                }
                return false;

            }

        }

        // If there is no error message, return true.
        return true;

    }

    // Method to parse through the form elements for jax-based validator attributes and conditions.
    this.parseFormElements = function(tag) {

        // Get the form elements.
        var objs = document.getElementsByTagName(tag);

        // Loop through the form elements, parsing the jax-based validators and setting the global validator array.
        for (var i = 0; i < objs.length; i++) {

            var obj = objs[i];

            if (obj.getAttribute('jax')) {

                // Check if the validator has multiple conditions.
                if (obj.getAttribute('jax').indexOf('&') != -1) {
                    objConds = obj.getAttribute('jax').split('&');
                } else {
                    objConds = new Array(obj.getAttribute('jax'));
                }

                for (var j = 0; j < objConds.length; j++) {
                    // Check if the validator has a condition value or not.
                    if (objConds[j].indexOf('|') != -1) {
                        cond = objConds[j].substring(0, objConds[j].indexOf('|'));
                        condVal = objConds[j].substring(objConds[j].indexOf('|') + 1);
                    } else {
                        cond = objConds[j];
                        condVal = null;
                    }

                    // Add the validator to the validators array.
                    this.validators.push(Array(obj.type, obj.name, obj.value, cond, condVal));
                }

            }

        }

    }

    // Method to validate the form element.
    this.formElementIsValid = function(elem) {

        var msg = null;

        switch (elem[3]) {

            // Alphanumeric pattern.
            case 'AlphaNum':
                if (!elem[2].match(/^\w+$/)) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not alphanumeric.';
                }
                break;

            // Alpha-only pattern.
            case 'Alpha':
                if (!elem[2].match(/^[a-zA-Z]+$/)) {
                msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field must contain only characters of the alphabet.';
                }
                break;

            // Between two values.
            case 'Between':
                var numAry = elem[4].split('|');
                if ((parseInt(elem[2]) <= parseInt(numAry[0])) || (parseInt(elem[2]) >= parseInt(numAry[1]))) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not between ' + numAry[0] + ' and ' + numAry[1];
                }
                break;

            // E-mail pattern.
            case 'Email':
                if (!elem[2].match(/[a-zA-Z0-9\.\-\_+%]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z]{2,4}/)) {
                    msg = 'The address in the ' + elem[1].replace(/_/g, ' ') + ' field is not a valid email.';
                }
                break;

            // Equal to value.
            case 'Equal':
                if (elem[2] != elem[4]) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field does not equal ' + elem[4];
                }
                break;

            // Greater than value.
            case 'GreaterThan':
                if (parseInt(elem[2]) <= parseInt(elem[4])) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not greater than ' + elem[4];
                }
                break;

            // String length greater than value.
            case 'Length':
                if (parseInt(elem[2].length) != parseInt(elem[4])) {
                    msg = 'The length of the ' + elem[1].replace(/_/g, ' ') + ' field does not equal ' + elem[4];
                }
                break;

            // String length between two values.
            case 'LengthBet':
                var numAry = elem[4].split('|');
                if ((parseInt(elem[2].length) <= parseInt(numAry[0])) || (parseInt(elem[2].length) >= parseInt(numAry[1]))) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not between ' + numAry[0] + ' and ' + numAry[1];
                }
                break;

            // String length greater than value.
            case 'LengthGT':
                if (parseInt(elem[2].length) <= parseInt(elem[4])) {
                    msg = 'The length of the ' + elem[1].replace(/_/g, ' ') + ' field is not greater than ' + elem[4];
                }
                break;

            // String length less than value.
            case 'LengthLT':
                if (parseInt(elem[2].length) >= parseInt(elem[4])) {
                    msg = 'The length of the ' + elem[1].replace(/_/g, ' ') + ' field is not less than ' + elem[4];
                }
                break;

            // Less than value.
            case 'LessThan':
                if (parseInt(elem[2]) >= parseInt(elem[4])) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not less than ' + elem[4];
                }
                break;

            // Value not empty.
            case 'NotEmpty':
                if ((elem[0] == 'radio') || (elem[0] == 'checkbox')) {
                    var elems = document.getElementsByTagName('input');
                    var counter = 0;

                    for (i = 0; i < elems.length; i++) {
                        if (elems[i].type == elem[0]) {
                            if (elems[i].checked) {
                                counter++;
                            }
                        }
                    }
                    if (counter == 0) {
                        if (elem[1].indexOf('[') != -1) {
                            elemName = elem[1].substring(0, elem[1].indexOf('['));
                        } else {
                            elemName = elem[1];
                        }
                        msg = 'The ' + elemName.replace(/_/g, ' ') + ' field must be checked.';
                    }
                } else if (elem[2].length < 1) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is empty.';
                }

                break;

            // Not equal to value.
            case 'NotEqual':
                if (elem[2] == elem[4]) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field cannot equal ' + elem[4];
                }
                break;

            // Numeric value.
            case 'Num':
                if (isNaN(elem[2])) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not a number.';
                }
                break;

            // Value matches regular expression.
            case 'RegEx':
                var regex = eval(elem[4]);
                if (!elem[2].match(regex)) {
                    msg = 'The ' + elem[1].replace(/_/g, ' ') + ' field is not in the correct format.';
                }
                break;

            default:
                msg = null;

        }

        // Return the error message, or null if there is no error.
        return msg;

    }

    // Method to check the length of the input of a form field and jump to the next one.
    this.checkLength = function(obj) {

        if (obj.value.length == obj.maxLength) {
            var next = obj.tabIndex;
            if (next < this.fo.length) {
                this.fo.elements[next].focus();
            }
        }

    }

    // Method to convert a string from a form field input into a friendly URL, passing it to another form field.
    this.convertURL = function(subj, targ, sep) {

        sub = eval('this.fo.' + subj);
        tar = eval('this.fo.' + targ);

        if (sep != null) {
            urlAry = sub.value.split(sep);
            val = '';
            for (var i = 0; i < urlAry.length; i++) {
                val = val + '/' + slug(urlAry[i]);
            }
            tar.value = val.replace(/-\/-/g, '/');
        } else {
            tar.value = '/' + slug(sub.value);
        }

    }

    // Method to quickly perform a checkbox validation to make sure at least one checkbox is checked.
    this.checkValidate = function(elem) {

        chk = document.getElementsByTagName('input');
        counter = 0;

        for (i = 0; i < chk.length; i++) {
            if (chk[i].type == 'checkbox') {
                if (chk[i].checked) {
                    counter++;
                }
            }
        }

        if (counter == 0) {
            alert('Please select at least one ' + elem + '.');
            return false;
        } else {
            return true;
        }

    }

}


/**
 *
 * Jax Loader Component
 *
 */

// Function to load images.
function imageLoader(imgs) {

    if (imgs.constructor == Array) {
        for (var i = 0; i < imgs.length; i++) {
            imgToLoad = new Image();
            imgToLoad.src = imgs[i];
        }
    } else {
        imgToLoad = new Image();
        imgToLoad.src = imgs;
    }

}

// Function to add a function to the onload stack.
function addLoader(func) {

    // Get old onload function(s), if they exist.
    var oldOnLoad = window.onload;

    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function() {
            if (oldOnLoad) {
                oldOnLoad();
            }
            func();
        }
    }

}


/**
 *
 * Jax Tools Component
 *
 */

// Function to create dynamic pop up window, set to center window on screen by default.
function newWindow(url, name, wid, hgt, scr, res, stat, loc, mnu, tool, x, y) {

    if (screen) {
        widthOfScreen = screen.width;
        heightOfScreen = screen.height;
    }

    if ((x == null) || (y == null)) {
        midX = widthOfScreen / 2;
        midY = heightOfScreen / 2;
        midWid = wid / 2;
        midHgt = hgt / 2;
        x = midX - midWid;
        y = midY - midHgt;
    }

    windowOpts = 'width=' + wid + ',height=' + hgt + ',scrollbars=' + scr + ',resizable=' + res + ',status=' + stat + ',location=' + loc + ',menubar=' + mnu + ',toolbar=' + tool + ',left=' + x + ',top=' + y;
    popUpWindow = window.open(url, name, windowOpts);

}

// Function to convert a string to an SEO slug.
function slug(str) {

    slg = str.toLowerCase();
    slg = slg.replace(/\&/g, 'and');
    slg = slg.replace(/([^a-zA-Z0-9 \-\/])/g, '');
    slg = slg.replace(/ /g, '-');
    slg = slg.replace(/-*-/g, '-');

    return slg;

}


/**
 *
 * Jax XMLHttp Component
 *
 */

// Prototype for the JaxXmlHttp object and its methods and properties.
function JaxXmlHttp() {

    // Create a new request object.
    if (window.XMLHttpRequest) {
        request = new XMLHttpRequest();
    } else {
        request = false;
    }

    // Method to execute a GET request.
    this.getRequest = function(url, func) {

        // Set and send the request, setting the function to execute on the return of a response.
        request.open('GET', url, true);
        request.onreadystatechange = func;
        request.send(null);

    }

    // Method to execute a POST request.
    this.postRequest = function(formObj, func, act) {

        params = '';

        // Loop through the form's elements to assemble the POST parameters.
        for (i = 0; i < formObj.elements.length; i++) {
            if (i == 0) {
                params += formObj.elements[i].name + '=' + formObj.elements[i].value;
            } else {
                params += '&' + formObj.elements[i].name + '=' + formObj.elements[i].value;
            }
        }

        if (act == null) {
            act = formObj.action;
        }

        // Set and send the request, setting the function to execute on the return of a response.
        request.open('POST', act, true);
        request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        request.setRequestHeader('Content-length', params.length);
        request.setRequestHeader('Connection', 'close');
        request.onreadystatechange = func;
        request.send(params);

    }

}