// Bam.js library is a product of MLB.com / MLB Advanced Media Inc.
// Any use of this code base outside or w/o written permission of MLB.com is prohibited
/*
	Template for non-loading lib
	subobject: (function(){
		var _self = {
			//Memory Loader (run once)
			activate: function() {
				(function() {
					//Main content
					delete _self.activate; //This line  MUST remain on the bottom of the block to ensure complete package load!!!
				})()
			}
		}
		return _self;
   })()
*/
(function(){
	var bam = {};	
	window.bam = bam = (function() {
		//Private function to lookup document css styles by href
		var _findStyle = function(href) {
			var styles = document.styleSheets,
				stLen = styles.length - 1,
				cStyle = null;
			if(stLen >= 0) {				
				do {
					cStyle = styles[stLen];
					if(!!cStyle.href && cStyle.href.lastIndexOf(href) > -1) {
						return cStyle;	
					}
				} while(stLen--);
			}
			return null;
		};
		//Prevents modules from being requested twice
		var _modules = [];
			_modules.isLoaded = function(path) {				
				var _out = false,
				_l = this.length-1,
				_c = null;
				if(_l >= 0) {
					do {
						_c=_modules[_l];
						if(!!_c && _c === path) {
							_out=true;	break;
						}
					} while(_l--);
				}
				return _out;
			};
		var _bam = {			
			//Sets a local path for packages to load dependencies
			homePath: "/shared/scripts/bam/",
			//Extends functionality of the bam namespace
			/* Ex:
				 bam.extend({
					utils: {
						//... utils code	
					}
				});
				Then access it by - bam.util
			*/			
			extend: function() {
				var ext = null;
				var obj = null;
				if(arguments.length>1){obj=arguments[0];ext=arguments[1];}else{obj=_bam;ext=arguments[0];}
				if(typeof(ext) === "object" && !!ext) {
					for(var i in ext) {
						if (!ext.hasOwnProperty || ext.hasOwnProperty(i)) {
							if(typeof(ext[i]) === "object") {
								if(!obj[i] || !!obj[i].path) { //If backwards
									obj[i] = ext[i];
									if(arguments.length === 1){obj[i].packageName = "bam." + i;}
								} 
							}
						}
					}
				}
			},
			// Appends functions in bulk to an object
			augment: function() {
				var ext = null;
				var obj = null;
				if(arguments.length>1){obj=arguments[0];ext=arguments[1];}else{obj=_bam;ext=arguments[0];}
				if(typeof(ext) === "object" && !!ext) {
					for(var i in ext) {
						if (!ext.hasOwnProperty || ext.hasOwnProperty(i)) {
							if(typeof(ext[i]) === "function") {
								if(!obj[i]) {
									obj[i] = ext[i];
								}
							}
						}
					}
				}
			},
			// (DEPRICATED) This function resembles Java import functionality for a package sub component
			// It activates a package subcomponent if it hasn't been activated yet
			// Usage: bam.imports(bam.dom);
			imports: function() {
				function _syncLoad(obj) {
					if(typeof(obj) === "object" && !!obj.lib) {
						var path = _bam.homePath + obj.path;
						delete _bam[obj.lib];
						_bam.loadSync(path);
					}
				}
				if(arguments.length > 1) {
					var aLen = arguments.length-1;
					do {
						_syncLoad(arguments[aLen]);
					} while(aLen--);
				} else {
					_syncLoad(arguments[0]);
				}
			},			
			//This function loads stand alone remote bam package (async)
			load: function(path, cb) {
				if(typeof(path) === "string") {
					if(!_modules.isLoaded(path)) {
						$.getJSON(path, function(json){
							bam.extend(json);
							_modules.push(path);
							if(!!cb && typeof(cb) === "function") {
								cb();
							}
						});
					} else {
						if(!!cb && typeof(cb) === "function") {
							cb();
						}
					}
				}
			},
			loadSync: function() {
				function _syncLoad(path) {
					$.ajax({
						type: "GET",
						url: path,
						dataType: "json",
						async:false,
						success: function(json) {
							bam.extend(json);
							_modules.push(path);
						}
					});
				}
				if(arguments.length > 1) {
					var aLen = arguments.length-1, _a=0;
					do {						
						if(!_modules.isLoaded(arguments[_a])) {
							_syncLoad(arguments[_a]);
						}
					} while(_a++ < aLen);
				} else {
					if(!_modules.isLoaded(arguments[0])) {
						_syncLoad(arguments[0]);
					}
				}
			},
			//Loads and applies CSS stylesheet to a page
			loadCSS: function(){
				 var stylePath;				
				 var aLen = arguments.length-1, _a=0;
				 if(aLen >= 0) {
					 var _head = document.getElementsByTagName("head")[0], 
					 	 _link = document.createElement("link"),
						 cLink = null;
						 _link.setAttribute("rel", "stylesheet");
						 _link.setAttribute("type", "text/css");
					 do {	 
						  if(!_findStyle(arguments[_a])){
							   stylePath = arguments[_a];
							   if(typeof(stylePath) === "string") {
								   cLink = _link.cloneNode(true);
								   cLink.setAttribute("href", stylePath);
								   _head.appendChild(cLink);
							   }
						  }
					 } while(_a++ < aLen);
				 }
             },
			//This function unloads/removes a stylesheet from a document based on href path specified
			unloadCSS: function() {							 
				 var styleSheet = null, 
				 	 owner = null,
					 parent = null;				 
				 var aLen = arguments.length-1;
				 if(aLen >= 0) {
					 do {
						  if(!!(styleSheet = _findStyle(arguments[aLen]))){
							   //First disable it
							   styleSheet.disabled = true;
							   //Then remove it
							   owner = (!!styleSheet.owningElement)?styleSheet.owningElement:styleSheet.ownerNode;
							   parent = (!!owner.parentElement)?owner.parentElement:owner.parentNode;
							   parent.removeChild(owner);
						  }
					 } while(aLen--);
				 }
			 },			 
			// bam.clone() makes a copy of the passed object and returns it.
			// If the passed object is not of type "object" or is null, an error is thrown
			clone: function(obj){
				if(typeof(obj)==="object"&&!!obj){
					function F(){}
					F.prototype = obj;
					return new F();
				} 
				else {
					throw new Error("bam.clone() was called with an invalid or null argument.");	
				}
			}
		};
		return _bam;
	})();
})();
//Backwards compat code
bam.collections= 	{path:"bam.collections.js", lib:"collections"};
bam.cookies= 		{path:"bam.cookies.js", lib:"cookies"};
bam.datetime= 		{path:"bam.datetime.js", lib:"datetime"};
bam.dom= 			{path:"bam.dom.js", lib:"dom"};
bam.filters= 		{path:"bam.filters.js", lib:"filters"};
bam.forms= 			{path:"bam.forms.js", lib:"forms"};
bam.soap= 			{path:"bam.soap.js", lib:"soap"};
bam.url= 			{path:"bam.url.js", lib:"url"};
bam.validation= 	{path:"bam.validation.js", lib:"validation"};
bam.xml= 			{path:"bam.xml.js", lib:"xml"};

bam.extend({
//Objects utils
	object: {
		typeOf: function(obj) {
			var out = "";
			if(typeof(obj) === "object") {
				switch(true) {
					case (!obj): out = "null"; break;
					case (obj instanceof Date): out = "date"; break;
					case (obj instanceof Array): out = "array"; break;
					case (!!obj.tagName): out = obj.tagName.toLowerCase(); break;
					case (typeof(obj.nodeType)!=="undefined"): out = "xml"; break;
					default: out = "object";
				}
				if((obj instanceof Date) && isNaN(obj)) {
					out = "NaN";	
				}
			} else {
				if(typeof(obj) === "number" && isNaN(obj)) {
					out = "NaN";	
				} else {
					out = typeof(obj);
				}
			}
			return out;
		}
	},
//String extensions
	string: (function(){
		var _self = {			
			trim: function(str) {
				if(typeof(str) === "string"){return str.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1");}
			},
			equals: function(str, str2) {
				if(typeof(str) === "string" && typeof(str2) === "string"){return str === str2;}
			},
			equalsIgnoreCase: function(str, str2) {
				if(typeof(str) === "string" && typeof(str2) === "string"){return str.toLowerCase() === str2.toLowerCase();}
			},
			toCharArray: function(str) {
				if(typeof(str) === "string"){
					var sl = str.length-1;
					var out = [];
					if(sl>=0){do {out.push(str.charAt(sl));} while(sl--);}
					return out.reverse();
				}
			},
			instr: function(str, from, to, val) {
				var _out = str;
				if(typeof(str) === "string"){
					if((!isNaN(from)) && (from >= 0) && (from <= str.length)) {
						if((!isNaN(to)) && (to >= 0) && (to <= str.length)) {
							var _tmp = str.substring(0, from);
							_tmp += val;
							_tmp += str.substring(to);
							_out = _tmp;
						}
					}
				}
				return _out;
			},			
			StringBuffer: function(str) {
				var _out = [],
					_that = this;
				this.length = 0;
				this.append = function(obj) {
					if(!!obj) {
					var _tmp = String(obj);
					_that.length += _tmp.length;
					_out = _out.concat(bam.string.toCharArray(_tmp));
					}
					return _that;
				};
				this.replace = function(start, end, rplStr) {
					if(bam.object.typeOf(rplStr) === "string" && 
					(bam.object.typeOf(start) === "number" && (start >= 0 && start <= _that.length)) &&
					(bam.object.typeOf(end) === "number" && (end > start && end <= _that.length))
					) {
						var _tmp = _that.toString();
						_tmp = bam.string.instr(_tmp, start, end, rplStr);
						_that.clear();
						_that.append(_tmp);
					}
					return _that;
				};
				this.remove = function(start, end) {
					if(!!end) {
						_that.replace(start, end, "");
					} else {
						_that.replace(start, _that.length, "");
					}					
					return _that;
				};
				this.reverse = function() {
					_out.reverse();
					return _that;
				};
				this.clear = function() {
					_that.length = 0;
					_out = [];
					return _that;
				};
				this.toString = function() {
					return _out.join("");
				};
				if(!!str) {
					_that.append(str);
				}
			},
			//escape HTML
			escapeHTML: function(htmlStr) {
				var _out = htmlStr;
				if(typeof(htmlStr) === "string") {
					//Prevent double escapement
					var _rxEscaped = /&\w*;/g;
					var _escMatch = null;
					while(!!(_escMatch = _rxEscaped.exec(_out))) {
						_out = bam.string.instr(_out, _escMatch.index, _escMatch.index + _escMatch[0].length, escape(_escMatch[0]));
						_rxEscaped.input = _out.substring(_escMatch.lastIndex);
					}
					_out = _out.replace(/&/g, "&amp;");
					_out = _out.replace(/</g, "&lt;");
					_out = _out.replace(/>/g, "&gt;");
					_out = _out.replace(/"/g, "&quote;");
					//Restore escaped pre-encoded tokens
					_out = unescape(_out);
				}
				return _out;
			},
			//Unescape HTML to it's original state
			unescapeHTML: function(htmlStr) {
				var _out = 	htmlStr;
				if(typeof(htmlStr) === "string") {
					var _htmlTokens = [[/&lt;/g, "<"], [/&gt;/g, ">"], [/&amp;/g, "&"], [/&quote;/g, "\""]];
					var _t = _htmlTokens.length-1, _c = null;
					do {
						_c = _htmlTokens[_t];
						_out = _out.replace(_c[0], _c[1]);
					} while(_t--);
				}
				return _out;
			}
		};
		return _self;
	})()
});