logEnabled = true;
toObjFunctionsEnabled = true;

// Check to see if element exist
jQuery.fn.exists = function(){return jQuery(this).length>0;}

// Writes a log message to the console window, if available
// Set window.logEnabled = false to disallow logging (true by default)
// msg = message to output
function log(msg) { if (logEnabled === undefined || logEnabled) try { console.log(msg); } catch(e) { } return msg; }

// String extension - indicates whether a string starts with the given string
// str = string to check for
String.prototype.startsWith = function(str) { return this.match(new RegExp("^" + str)) == str; };

// String extension - indicates whether a string ends with the given string
// str = string to check for
String.prototype.endsWith = function(str) { return this.match(new RegExp(str + "$")) == str; };

// String extension - returns a new string describing a CSS class reference
String.prototype.asCssClass = function() { return "." + this; };

// String extension - returns a new string describing a CSS ID reference
String.prototype.asCssId = function() { return "#" + this; };

// String extension - wraps HTML tag markup around 'this' and returns a new string (see HtmlUtility.tag)
// t = HTML tag name
// attrs = object describing HTML attributes (optional)
String.prototype.wrapHtml = function(t, attrs) { return html.tag(t, attrs, this); }

// Array extension - Adds an item to the end of an array and returns the array
// Very similar to the built-in Array.push() method except that it returns the array rather than the new length.
// This method changes the original array.
// obj = item to add
Array.prototype.add = function(obj) { this[this.length] = obj; return this; };

// Array extension - Adds an item to the end of an array if the item is truthy
// This method changes the original array.
// obj = item to evaluate and add
Array.prototype.addIf = function(obj) { return obj ? this.add(obj) : this; };

// Array extension - runs a function for each item in the array and returns the array
// Very similar to but smaller than Array.forEach - also, Array.forEach isn't universally supported
// fn(item) = function to run for each item in the array
Array.prototype.each = function(fn) { for (var i = 0; i < this.length; i++) { fn.call(this[i], i); } return this; };

// Array extension - Alias for Array.add()
Array.prototype.append = Array.prototype.add;

// Array extension - Adds an item to the beginning of an array and returns a new array
// This method does not update the original array
// obj = item to add
Array.prototype.prepend = function(obj) { var ret = [obj]; this.each(function(){ ret.add(this); }); return ret; };

// Array extension - runs a function for each item in the arary and returns a new array
// The new array contains all of the items from the source array that returned positive from the referenced function (filter)
// Very similar to and possibly redundant with Array.filter - research needed
// fn(item) = filter function
Array.prototype.where = function(fn) { var arr = []; this.each(function(i){ if (fn.call(this, i)) arr.add(this); }); return arr; };

// Array extension - Alias for Array.where()
Array.prototype.filter = Array.prototype.where;

// Array extension - inverse of Array.where - runs a function for each item in the arary and returns a new array
// The new array contains none of the items from the source array that returned positive from the referenced function (filter)
// fn(item) = filter function
Array.prototype.exceptWhere = function(fn) { var arr = []; this.each(function(i){ if (!fn.call(this, i)) arr.add(this); }); return arr; };

// Alias for Array.exceptWhere()
Array.prototype.except = Array.prototype.exceptWhere;

// Array extension - runs a function for each item in the array and returns a new array
// The new array contains a list of results from the referenced function (translation)
// fn(item) = translation function
Array.prototype.select = function(fn) { var arr = []; this.each(function(i){ arr.add(fn.call(this, i)); }); return arr; };

// Array extension - returns the first item in the array after calling Array.where(fn) (if applicable)
// fn(item) = filter function (optional)
Array.prototype.first = function(fn) { return fn ? this.where(fn)[0] : this[0]; };

// Array extension - returns the last item in the array after calling Array.where(fn) (if applicable)
// fn(item) = filter function (optional)
Array.prototype.last = function(fn) { var arr = fn ? this.where(fn) : this; return arr[arr.length - 1]; };

// Array extension - returns true if the array contains a given item or false otherwise
// obj = item to look for
// fn(index) = function to call when the matching item in the array is found (optional - 'this' context is the array)
Array.prototype.contains = function(obj, fn) {
	var that = this, arr = this.where(function(){ return this == obj; });
    if (fn) arr.each(function(i){ fn.call(that, i); });
	return arr.length > 0;
};

// Function extension - Returns a list of argument names for a function
Function.prototype.getArgumentNames = function() { return this.toString().match(/\((.+)\)/)[1].split(",").select(function(){ return this.replace(/\s+/g, ""); }); };

// Function extension - Returns an object with value properties for each named argument for a function
// args = list of argument values to inject into the list of named values
Function.prototype.getNamedArguments = function(args) { var ret = {}; this.getArgumentNames().each(function(i){ ret[this] = args[i]; }); return ret; };

// Function extension - Returns a list of objects with .key and .value properties, where the keys are the names of the arguments for the function
// args = list of argument values to inject into the list of named values
Function.prototype.getArgumentsDictionary = function(args) { var names = this.getArgumentNames(); return names.select(function(i){ return { key: names[i], value: args[i] }; }); };

// Add some aliases for things that I tend to spell wrong or don't like typing;
var Regex = window.RegExp;

// Add JSON methods if the browser doesn't already know them
var JSON = window.JSON || {};

// Returns a string representation of a JSON object
JSON.stringify = JSON.stringify || function(obj) {
	var t = typeof (obj);
	if (t != "object" || obj === null) { // simple data type  
        if (t == "string") obj = '"' + obj + '"';
        return String(obj);
    } else { // recurse array or object  
        var n, v, json = [], arr = (obj && obj.constructor == Array);  
        for (n in obj) {
            v = obj[n]; t = typeof(v);  
            if (t == "string") v = '"' + v + '"';  
            else if (t == "object" && v !== null) v = JSON.stringify(v);  
            json.push((arr ? "" : '"' + n + '":') + String(v));  
        }  
        return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");  
    }
};

// Builds an object from a JSON string representation
JSON.parse = JSON.parse || function (str) { return eval(str); };

// Contains methods for working with diagnostic timers
var TimerUtility = function() {

	// Starts a timer with a given name
	// name = name of the timer
	this.startTimer = function(name) {
		this.timers = this.timers || {};
		this.timers[name] = new Date();
		return this;
	};
	
	// Returns the ellapsed time since a timer was started or -1
	// name = name of the timer to check on
	this.checkTimer = function(name) { return (this.timers && this.timers[name]) ? ((new Date()) - this.timers[name]) : -1; };
	
	// Writes a log message indicating the ellapsed time for a timer
	// name = name of the timer to cehck on
	this.logTimer = function(name) { return log(name + " time: " + this.checkTimer(name)); };
	return this;
};
var timerUtil = new TimerUtility();

// Contains general methods for interacting with various objects
// Note: These methods are bundled into ObjectUtility because some things read from the list of properties on objects and
// process them in order to do their work. When you add functions using Object.prototype, those function properties are exposed
// and may cause side effects. For instance, ObjectUtility.tag() renders HTML showing prototype members on Object. Developers
// should be aware of this and use .prototype accordingly.
var ObjectUtility = function() {

	// Returns a string describing all of the properties of an object
	// o = object to report on
	// fn(key, value) = callback to get each value string (optional)
	// sep = separator text for between values (optional)
	// includeNulls = indicates whether or not to report on null properties (optional)
	this.reportValues = function(o, fn, sep, includeNulls) {
		var ret = "";
		if (fn === undefined) fn = function(key, val) { return " " + key + "='" + val + "'"; };
		for(var x in o) { if (o[x] || includeNulls) ret += fn(x, o[x]); }
		return ret + (sep ? sep : "");
	};
	
	// Returns the value of val, whether val is an object or a function
	// If val is a function, all arguments after val ar passsed to val()
	// val = object or function to get the value from
	this.getValue = function(val) { return typeof val == "function" ? val(arguments.length > 1 ? arguments.slice(1) : null) : val; };

	// Strips/replaces wrapping quotes and encoded characters in a string and returns a new string
	// str = source string
	this.unstr = function(str) { return str ? str.substring(1, str.length-1).replace(/\\'/g, "'").replace(/\\"/g, "\"") : str; };

	// Tries to create a new object from a string representation of an object
	// Similar to JSON.parse() except that this tries to instantiate objects with functions as well.
	// Set window.toObjFunctionsEnabled = true to allow objects with methods (strict JSON parsing happens by default)
	// str = string representation of an object
	this.strToObj = function(str) { return str ? toObjFunctionsEnabled ? (new Function("return " + str))() : JSON.parse(str) : str; };
	
	// Returns a string listing all the elements in an array
	// Possibly redundant - check if built-in Array.join works first
	// arr = source array
	// sep = separator string for between elements (optional)
	// prepend = indicates whether or not to prepend the separator string (optional)
	this.join = function(arr, sep, prepend) {
		if (bail = arr === undefined || arr === null || !arr.length) return "";
		sep = sep ? sep : ""; var ret = prepend ? sep : "";
		for (var i = 0; i < arr.length; i++) {
			ret += arr[i] + (i < arr.length -1) ? sep : "";
		}
		return ret;
	};
	
    // Adds properties from obj2 into obj1 and returns obj1
    // obj1 = object to add properties into
    // obj2 = object to receive properties from
    this.fill = function(obj1, obj2) {

		// ** TODO: remove jQuery dependency on ObjectUtility.fill()

        if (!jQuery) throw "jQuery dependency in ObjectUtility.fill()";
        return jQuery.extend(true, obj1, obj2);
    };
	return this;
};
var objectUtil = new ObjectUtility();

// Contains methods for creating and working with cookies
var CookieUtility = function() {
	
	// Encodes a value into a string that can be used in a cookie (returns the new value)
	// str = value to encode
	this.encode = function(str) {
		var fn = encodeURIComponent ? encodeURIComponent : escape;
		return fn(str).replace(/\+/g, '%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40');
	};
	
	// Decodes a value from a cookie that was previously encoded using CookieUtility.encode() (returns the new value)
	// str = value to decode
	this.decode = function(str) { return (decodeURIComponent ? decodeURIComponent : unescape)( str.replace(/\+/g, ' ')); };
	
	// Creates a new cookie with a given name and value
	// name = name to assign to the new cookie
	// val = value to add into the cookie (the value will be automatically encoded)
	// days = number of days before the cookie expires
	this.create = function(name, val, days) {
		var ex = "";
		if (days) {
			var d = new Date();
			d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
			ex = "; expires=" + d.toGMTString();
		}
		return document.cookie = name + "=" + this.encode(val) + ex + "; path=/";
	};
	
	// Reads the value of a named cookie
	// name = name of the cookie to retrieve
	this.read = function(name) {
		var that = this, cookies = document.cookie.split(';'), ret = "";
		cookies.each(function(){
		    var matches = this.match(new Regex(name + "=(.*)"));
		    if (matches && matches.length > 1) ret = that.decode(matches[1]);
		});
		return ret;
	};
	
	// Removes a named cookie
	// name = name of the cookie to remove
	this.remove = function(name) { this.create(name, "", -1); return this; };
	return this;
};
var cookieUtil = new CookieUtility();

// Contains methods to create HTML strings
var HtmlUtility = function() {

	// Returns an HTML string for a given tag name and attributes
	// t = tag name
	// attrs = array of attribute names and values (optional)
	// inner = inner HTML (optional)
	this.tag = function(t, attrs, inner) { return "<" + t + objectUtil.reportValues(attrs) + ">" + (inner ? inner : "") + "</" + t + ">" };
	
	// Returns an HTML string for a given tag name by passing class and id attributes to tag()
	// t = tag name
	// c = class name (optional)
	// id = id value (optional)
	// inner = inner HTML (optional)
	this.smtag = function(t, c, id, inner) { return this.tag(t, { "class" : c, "id" : id }, inner); };
	
    // Generate a function for each simple tag in the list
    var that = this, simpleTags = ["tr", "td", "span", "div", "p", "label", "i", "b", "strong", "em", "blockquote", "ul", "li", "select"];
    simpleTags.each(function(){

        // Returns an HTML string for a 'this' tag by passing arguments to smtag()
        // c = class name (optional)
        // id = id value (optional)
        // inner = inner HTML (optional)
        var tag = this;
        that[tag] = function(c, id, inner) { return that.smtag(tag, c, id, inner); };
    });
    
	// Returns an HTML string for a link anchor by passing arguments to smtag()
	// c = class name (optional)
	// id = id value (optional)
    // href = href value for the link
	// inner = inner HTML (optional)
    this.a = function(c, id, href, inner) { return this.tag("a", { "href" : href, "class" : c, "id" : id }, inner); };
	
	// Returns an HTML string for a checkbox (INPUT) by passing arguments to smtag()
	// c = class name (optional)
	// id = id value (optional)
	// inner = inner HTML (optional)
	// checked = whether the checkbox is checked (optional)
	this.check = function(c, id, value, inner, checked, name) { return this.tag("input", { "type" : "checkbox", "class" : c, "id" : id, "checked" : checked, "value" : value, "name" : name}, inner); };
	
	// Returns an HTML string for a select option (OPTION) by passing arguments to tag()
	// inner = inner HTML (optional)
    // value = value attribute value (optional)
	// selected = whether the option is selected (optional)
	this.option = function(inner, value, selected) { return this.tag("option", { "selected":selected, "value":value }, inner); };
    
    // Returns an HTML string for an input field (INPUT) by passing arguments to tag()\
    // t = tag name
    // name = name attribute value (optional)
    // value = value attribute value (optional)
    // c = class name (optional)
    // id = id value (optional)
    // inner = inner HTML (optional)
    this.input = function(type, name, value, c, id, inner, title) { return this.tag("input", { "type":type, "name":name, "value":value, "class":c, "id":id, "title":title }, inner); };
	
	// Returns an HTML string surrounding an inner HTML string with new DIV elements
	// inner = inner HTML to surround (optional)
	// prependClass = class name for the prepended DIV (optional)
	// appendClass = class name for the appended DIV (optional)
	this.surround = function(inner, prependClass, appendClass) { return this.div(prependClass || "left") + (inner ? inner : "") + this.div(appendClass || "right"); };
	return this;
};
var html = new HtmlUtility();

// Describes a unit test assertion result
// msg = message describing the assertion
// passed = whether or not the assertion passed
var TestAssertion = function(msg, passed){
    this.message = msg;
    this.passed = passed;
    
    // Outputs a log message describing the assertion result
    this.report = function(){
        log((this.passed ? "  PASSED" : "* FAILED") + " - " + msg);
        return this;
    };
    return this;
};

// Describes a unit test set - contains methods for running unit test assertions
var TestUtility = function(){
    this.assertions = [];
    
    // Adds an assertion result to the list of assertions for this test set
    // exp = function or value to evaluate
    // msg = message describing the assertion
    this.assert = function(exp, msg){
        var passed = objectUtil.getValue(exp);
        this.assertions[this.assertions.length] = (new TestAssertion(msg, passed)).report();
        return passed;
    };
    
    // Logs a test summary and returns true if all tests succeeded
    this.report = function(){
        var numPassed = 0;
        this.assertions.each(function(){ if (this.passed) ++numPassed; });
        var passed = this.assertions.length == numPassed;
        log(">> Ran " + this.assertions.length + " assertions. " + numPassed + " passed.");
        log(">> Test pass " + (passed ? "succeeded." : "FAILED."));
        return passed;
    };
    return this;
};

// Takes the child item(s) to fit into the parent width
// For example take the list items (child) fit into the unordered list (parent)
// fixWidth(".child_class", "#parent_id");
function fixWidth(child, parent) {
	var x = $(child).length;var y = 0;var z = $(parent).outerWidth();
	var add = function () {
		var s = z-y;
		var t = s/x;
		$(child).each(function () {
			var u = $(this).width();
			$(this).width(u+t);	
		})
	}
	$(child).each(function (i) {
		var r = $(this).outerWidth();
		y = y+r;
		(x == i+1)?add():"";
	});
}

