window.$C = window.$C || {};

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
	var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
	this.Class = function(){};
	
	// Create a new Class that inherits from this class
	Class.extend = function(prop) {
		var _super = this.prototype;
   
		// Instantiate a base class (but only create the instance,
		// don't run the init constructor)
		initializing = true;
		var prototype = new this();
		initializing = false;
   
		// Copy the properties over onto the new prototype
		for (var name in prop) {
			// Check if we're overwriting an existing function
			prototype[name] = typeof prop[name] == "function" &&
			typeof _super[name] == "function" && fnTest.test(prop[name]) ?
				(function(name, fn){
					return function() {
						var tmp = this._super;
       
						// Add a new ._super() method that is the same method
						// but on the super-class
						this._super = _super[name];
           
						// The method only need to be bound temporarily, so we
						// remove it when we're done executing
						var ret = fn.apply(this, arguments);       
						this._super = tmp;
           
						return ret;
					};
				})(name, prop[name]) : 
				prop[name];
		}
   
		// The dummy class constructor
		function Class() {
			// All construction is actually done in the init method
			if ( !initializing && this.init )
				this.init.apply(this, arguments);
		}
   
		// Populate our constructed prototype object
		Class.prototype = prototype;
		   
		// Enforce the constructor to be what we expect
		Class.constructor = Class;
		
		// And make this class extendable
		Class.extend = arguments.callee;
   
		return Class;
	};
})();

(function(){
	/* Cross-Browser Split 1.0.1
	(c) Steven Levithan <stevenlevithan.com>; MIT License
	An ECMA-compliant, uniform cross-browser split method */

	var cbSplit;

	// avoid running twice, which would break `cbSplit._nativeSplit`'s reference to the native `split`
	if (!cbSplit) {

	cbSplit = function (str, separator, limit) {
	    // if `separator` is not a regex, use the native `split`
	    if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
	        return cbSplit._nativeSplit.call(str, separator, limit);
	    }

	    var output = [],
	        lastLastIndex = 0,
	        flags = (separator.ignoreCase ? "i" : "") +
	                (separator.multiline  ? "m" : "") +
	                (separator.sticky     ? "y" : ""),
	        separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
	        separator2, match, lastIndex, lastLength;

	    str = str + ""; // type conversion
	    if (!cbSplit._compliantExecNpcg) {
	        separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
	    }

	    /* behavior for `limit`: if it's...
	    - `undefined`: no limit.
	    - `NaN` or zero: return an empty array.
	    - a positive number: use `Math.floor(limit)`.
	    - a negative number: no limit.
	    - other: type-convert, then use the above rules. */
	    if (limit === undefined || +limit < 0) {
	        limit = Infinity;
	    } else {
	        limit = Math.floor(+limit);
	        if (!limit) {
	            return [];
	        }
	    }

	    while (match = separator.exec(str)) {
	        lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser

	        if (lastIndex > lastLastIndex) {
	            output.push(str.slice(lastLastIndex, match.index));

	            // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
	            if (!cbSplit._compliantExecNpcg && match.length > 1) {
	                match[0].replace(separator2, function () {
	                    for (var i = 1; i < arguments.length - 2; i++) {
	                        if (arguments[i] === undefined) {
	                            match[i] = undefined;
	                        }
	                    }
	                });
	            }

	            if (match.length > 1 && match.index < str.length) {
	                Array.prototype.push.apply(output, match.slice(1));
	            }

	            lastLength = match[0].length;
	            lastLastIndex = lastIndex;

	            if (output.length >= limit) {
	                break;
	            }
	        }

	        if (separator.lastIndex === match.index) {
	            separator.lastIndex++; // avoid an infinite loop
	        }
	    }

	    if (lastLastIndex === str.length) {
	        if (lastLength || !separator.test("")) {
	            output.push("");
	        }
	    } else {
	        output.push(str.slice(lastLastIndex));
	    }

	    return output.length > limit ? output.slice(0, limit) : output;
	};

	cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
	cbSplit._nativeSplit = String.prototype.split;

	} // end `if (!cbSplit)`

	$C.split = cbSplit;
	
})();


(function($){
	
	/* Custom event handling that is used by our Classes */
	$.fn.observe = function(event, fn, context) {
		return this.bind(event, function(e){
			return fn.call(context, e);
		});
	}
	
	$C.delegate = $C.delegate || function(event, selector, root, fn, context) {
		$(root).bind(event, function(e){
			var el = $(e.srcElement || e.target).closest(selector);
					
			if (el.length)
				return fn.call(context || el[0], e, el[0]);
		});
	}

	/* global instance counter for all Chegg widgets */
	$C.instanceCounter = 0;

	/* max value of an array */
	$C.max = function( array ){
	    return Math.max.apply( Math, array );
	};

	/* min value of an array */
	$C.min = function( array ){
	    return Math.min.apply( Math, array );
	};

	$C.getMaxIndex = function(){
		var children = $($C.rootElement).children();
		var zIndex = [10];
		for(var i=0; i< children.length; i++) {
			zIndex.push(+(children[i].style.zIndex) || 0);
		}
		return $C.max(zIndex);
	};

	$C.log = function(){
		var w = window;
		return {
			add: function(m) { w.console && w.console.log(m) },
			js: function() { w.console && w.console.profile() },  
			jsEnd: function() { w.console && w.console.profileEnd() },
			prof: function(code) {
				if ( w.console ) {
					w.console.profile();
					try { code() } catch(err) { };
					console.profileEnd();
				}
			}
		};
	}();

	/* selection range */
	$C.setSelectionRange = function(input, start, offset){
		input = $(input)[0];
		
		if (input.setSelectionRange) {
			input.setSelectionRange(start, offset);
		}
		else if (input.createTextRange) {
			var range = input.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start+offset);
			range.moveStart('character', start);
			range.select();
		}
	}



	$C.setCookie = function ( name, value, expires, path, domain, secure ) {
		var expires = new Date( (new Date()).getTime() + expires * 1000 * 3600 * 24 );
		var cookie = [];
		
		cookie.push( name + '=' + escape(value) );
		if (expires) cookie.push( 'expires=' + expires.toGMTString() );
		if (path) cookie.push( 'path=' + (path) );
		if (domain) cookie.push( 'domain=' + domain );
		if (secure) cookie.push( 'secure' );
		
		document.cookie = cookie.join(';');
	};

	$C.getCookie = function( name ){
		if (!name.length) return null;
		
		var cookies = $C.split(String(document.cookie), ';');
		var curCookie = [];
		for(var i=0; i< cookies.length; i++) {
			curCookie = $C.split($.trim(cookies[i]), '=');
			if (curCookie[0] === name) {
				return unescape(curCookie[1]);
			}
		}
		return null;
	};
	
	
})(jQuery);


