/*
	Frank Marion, software@frankmarion.com.
	http://www.frankmarion.com

	Date Created:	15/03/2001 4:48:04 AM
	Last Modified:	Saturday, March 22, 2003 4:59:54 PM

	Function: A library of functions and methods that should exist but don't. Now they do.
*/

/* ------------------------------------------------------------------------ */
/* Type functions --------------------------------------------------------- */

// Internet Explorer holds references to objects which are not JavaScript objects, 
// and which produce errors if they are treated as JavaScript objects. 
// This is a problem because typeof identifies them as JavaScript objects. 
// The isAlien() function will return true if a is one of those alien objects.
function isAlien(a) {
   return isObject(a) && typeof a.constructor != 'function';
}

// isArray() returns true if a is an array, meaning that it was produced by the 
// Array constructor or by using the [ ] array literal notation.
function isArray(a) {
    return isObject(a) && a.constructor == Array;
}

// isBoolean(a) returns true if a is one of the boolean values, true or false.
function isBoolean(a) {
    return typeof a == 'boolean';
}

// isEmpty(a) returns true if a is an object or array or function containing no 
// enumerable members.
function isEmpty(o) {
    var i, v;
    if (isObject(o)) {
        for (i in o) {
            v = o[i];
            if (isUndefined(v) && isFunction(v)) {
                return false;
            }
        }
    }
    return true;
}

// isFunction(a) returns true if a is a function. Beware that some native functions in IE 
// were made to look like objects instead of functions. This function does not detect that.
function isFunction(a) {
    return typeof a == 'function';
}

// isNull(a) returns true if a is the null value.
function isNull(a) {
    return typeof a == 'object' && !a;
}

// isNumber(a) returns true if a is a finite number. It returns false if a is NaN or Infinite. 
// It also returns false if a is a string that could be converted to a number.
function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}

// isObject(a) returns true if a is an object, and array, or a function. It returns false if a 
// is a string, a number, a boolean, or null, or undefined.
function isObject(a) {
    return (a && typeof a == 'object') || isFunction(a);
}

// isString(a) returns true if a is a string.
function isString(a) {
    return typeof a == 'string';
}

// isUndefined(a) returns true if a is the undefined value. You can get the undefined value from 
// an uninitialized variable or from a missing member of an object.
function isUndefined(a) {
    return typeof a == 'undefined';
} 

/* ------------------------------------------------------------------------ */
/* String methods --------------------------------------------------------- */


// entityify() produces a string in which '<', '>', and '&' are replaced with their HTML
// entity equivalents.
function entityify(arg) {
        return this.replace(/&/g, "&amp;").replace(/</g,"&lt;").replace(/>/g, "&gt;");
}

// quote() produces a quoted string. This method returns a string which is like the original 
// string except that it is wrapped in quotes and all quote and backslash characters are 
// preceded with backslash.
function quote(arg) {
	var c, i, l = this.length, o = '"';
	for (i = 0; i < l; i += 1) {
		c = this.charAt(i);
		if (c >= ' ') {
			if (c == '\\' || c == '"') {
				o += '\\';
			}
			o += c;
		} else {
			switch (c) {
			case '\b':
				o += '\\b';
				break;
			case '\f':
				o += '\\f';
				break;
			case '\n':
				o += '\\n';
				break;
			case '\r':
				o += '\\r';
				break;
			case '\t':
				o += '\\t';
				break;
			default:
				c = c.charCodeAt();
				o += '\\u00' + Math.floor(c / 16).toString(16) +
					(c % 16).toString(16);
			}
		}
	}
	return o + '"';
}

// Remove leading and trailing whitespace
function Trim (arg) {
	return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}


/* ------------------------------------------------------------------------ */
/* Object functions ------------------------------------------------------- */
if (!isFunction(Function.apply)) {
    Function.method('apply', function (o, a) {
        var r, x = '____apply';
        if (!isObject(o)) {
            o = {};
        }
        o[x] = this;
        switch ((a && a.length) || 0) {
        case 0:
            r = o[x]();
            break;
        case 1:
            r = o[x](a[0]);
            break;
        case 2:
            r = o[x](a[0], a[1]);
            break;
        case 3:
            r = o[x](a[0], a[1], a[2]);
            break;
        case 4:
            r = o[x](a[0], a[1], a[2], a[3]);
            break;
        case 5:
            r = o[x](a[0], a[1], a[2], a[3], a[4]);
            break;
        case 6:
            r = o[x](a[0], a[1], a[2], a[3], a[4], a[5]);
            break;
        default:
            alert('Too many arguments to apply.');
        }
        delete o[x];
        return r;
    });
} 

if (!isFunction(Array.prototype.pop)) {
    Array.method('pop', function () {
        return this.splice(this.length - 1, 1)[0];
    });
}

if (!isFunction(Array.prototype.push)) {
    Array.method('push', function () {
        this.splice.apply(this,
            [this.length, 0].concat(Array.prototype.slice.apply(arguments)));
        return this.length;
    });
}

if (!isFunction(Array.prototype.shift)) {
    Array.method('shift', function () {
        return this.splice(0, 1)[0];
    });
}

if (!isFunction(Array.prototype.splice)) {
    Array.method('splice', function (s, d) {
        var max = Math.max,
            min = Math.min,
            a = [], // The return value array
            e,  // element
            i = max(arguments.length - 2, 0),   // insert count
            k = 0,
            l = this.length,
            n,  // new length
            v,  // delta
            x;  // shift count

        s = s || 0;
        if (s < 0) {
            s += l;
        }
        s = max(min(s, l), 0);  // start point
        d = max(min(isNumber(d) ? d : l, l - s), 0);    // delete count
        v = i - d;
        n = l + v;
        while (k < d) {
            e = this[s + k];
            if (!isUndefined(e)) {
                a[k] = e;
            }
            k += 1;
        }
        x = l - s - d;
        if (v < 0) {
            k = s + i;
            while (x) {
                this[k] = this[k - v];
                k += 1;
                x -= 1;
            }
            this.length = n;
        } else if (v > 0) {
            k = 1;
            while (x) {
                this[n - k] = this[l - k];
                k += 1;
                x -= 1;
            }
        }
        for (k = 0; k < i; ++k) {
            this[s + k] = arguments[k + 2];
        }
        return a;
    });
}

if (!isFunction(Array.prototype.unshift)) {
    Array.method('unshift', function () {
        this.splice.apply(this,
            [0, 0].concat(Array.prototype.slice.apply(arguments)));
        return this.length;
    });
} 

/* ------------------------------------------------------------------------ */
/* Object functions ------------------------------------------------------- */

// Retrieve a specific element by it's class
/*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com
*/

function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];      
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }   
    }
    return (arrReturnElements)
}

// Add, remove, check for or swap CSS classes
function cssjs (a,o,c1,c2){
	switch (a){
		case 'swap':
				o.className=!cssjs('check',o,c1)?o.className.replace(c2,c1):o.className.replace(c1,c2);
		break;
		case 'add':
				if(!cssjs('check',o,c1)){o.className+=o.className?' '+c1:c1;}
		break;
		case 'remove':
				var rep=o.className.match(' '+c1)?' '+c1:c1;
				o.className=o.className.replace(rep,'');
		break;
		case 'check':
				return new RegExp("(^|\s)" + c1 + "(\s|$)").test(o.className);
		break;
	}
}




