epiton.utils={};
epiton.classloader.addDependancy("utils.ajax");

epiton.utils.Object=function(){
	var _private={
		clone:function(obj){
		    if(obj == null || typeof(obj) != 'object') return obj;
			var temp = new obj.constructor(); // changed (twice)
		
			for(var key in obj)
				temp[key] = this.clone(obj[key]);
			
			return temp;
		}
	}
	var _public={
		clone:function(obj){
			if(obj){
				try{
					return eval(uneval(obj));
				}catch(e){}
				return _private.clone(obj);
			}else{
				return obj;
			}
		},
		isString:function(a) {
		    return typeof a == 'string';
		}
	}
	return _public;
}();

epiton.utils.Json=function(){
	var _public={
		isJson:function(json){
			if(json){
				if((/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json))){
					return true;
				}
			}
			return false;
		},
		eval:function(json){
			if(_public.isJson(json)){
				return eval("("+json+")");
			}
			return null;
		},
		serialize:function(obj){
			switch (typeof obj) {
			  case 'object':
			   if (obj) {
			    var list = [];
			    if (obj instanceof Array) {
			     for (var i=0;i < obj.length;i++) {
			      list.push(toJson(obj[i]));
			     }
			     return '[' + list.join(',') + ']';
			    } else {
			     for (var prop in obj) {
			      list.push('"' + prop + '":' + this.serialize(obj[prop]));
			     }
			     return '{' + list.join(',') + '}';
			    }
			   } else {
			    return 'null';
			   }
			  case 'string':
			   return '"' + obj.replace(/(["'])/g, '\\$1') + '"';
			  case 'number':
			  case 'boolean':
			   return new String(obj);
			 }
		}
	}
	return _public;
}();
epiton.utils.Cookie=function(){
	var _public={
		get:function(check_name){
			// first we'll split this cookie up into name/value pairs
			// note: document.cookie only returns name=value, not the other components
			var a_all_cookies = document.cookie.split( ';' );
			var a_temp_cookie = '';
			var cookie_name = '';
			var cookie_value = '';
			var b_cookie_found = false; // set boolean t/f default f
			var i=0;
			
			for ( i = 0; i < a_all_cookies.length; i++ )
			{
				// now we'll split apart each name=value pair
				a_temp_cookie = a_all_cookies[i].split( '=' );
				
				
				// and trim left/right whitespace while we're at it
				cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
			
				// if the extracted name matches passed check_name
				if ( cookie_name == check_name )
				{
					b_cookie_found = true;
					// we need to handle case where cookie has no value but exists (no = sign, that is):
					if ( a_temp_cookie.length > 1 )
					{
						cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
					}
					// note that in cases where cookie is initialized but no value, null is returned
					return cookie_value;
					break;
				}
				a_temp_cookie = null;
				cookie_name = '';
			}
			if ( !b_cookie_found )
			{
				return null;
			}
		},
		set:function( name, value, expireMins, path, domain, secure ){
			// set time, it's in milliseconds
			var today = new Date();
			today.setTime( today.getTime() );
			if ( expireMins )
			{
			expireMins = expireMins * 1000 * 60;
			}
			var expires_date = new Date( today.getTime() + (expireMins) );
			
			document.cookie = name + "=" +escape( value ) +
			( ( expireMins ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
			( ( path ) ? ";path=" + path : "" ) + 
			( ( domain ) ? ";domain=" + domain : "" ) +
			( ( secure ) ? ";secure" : "" );
		}
	}
	return _public;
}();


epiton.utils.Dom=function(){
	var _private={
		collateNodes:function(nodes,map){
			if(!nodes) return;
			var i=0;
			for(i=0;i<nodes.length;i++){
				var n=nodes[i];
				if(n.type=='radio' || n.type=='checkbox'){
					if(n.checked==true){
						map[n.name]=n.value;
					}else if(!map[n.name]){
						map[n.name]="";
					}
				}else{
					map[n.name]=n.value;
				}
			}
		},
		expandNodes:function(nodes,map){
			if(!nodes) return;
			var i=0;
			for(i=0;i<nodes.length;i++){
				var n=nodes[i];
				if(n.name){
					var val=map[n.name];
					if(val){
						if(n.nodeName=="SELECT"){
							var sc=n.getElementsByTagName('option');
							var j=0;
							for(j=0;j<sc.length;j++){
								var sjn=sc[j];
								if(sjn.value==val){
									sjn.selected=true;
								}else{
									sjn.selected=false;
								}
							}
						}else if(n.nodeName=="INPUT"){
							if(n.type=='radio'){
								if(n.value==val){
									n.checked=true;
								}else{
									n.checked=false;
								}
							}
						}
					}
				}
			}
		},
		collateFormTypeElements:function(el,map){
			if(!el) return;
			_private.collateNodes(el.getElementsByTagName('select'),map);
			_private.collateNodes(el.getElementsByTagName('input'),map);
		},
		setNodeValuesFromMap:function(el,map){
			_private.expandNodes(el.getElementsByTagName('select'),map);
			_private.expandNodes(el.getElementsByTagName('input'),map);
		}
	};
	var _public={
		renderIntoDiv:function(divId, nval){
			var _el=document.getElementById(divId);
			if(_el){
				if(nval){_el.innerHTML=nval;}
			}
		},
		renderIntoElement:function(el,nval){
			if(el){
				var _el=null;
				if(epiton.utils.Object.isString(el)){
					_el=document.getElementById(el);
				}else{
					_el=el;
				}
				if(_el&&nval){_el.innerHTML=nval;}
			}
		},
		createNode: function(ntype, nname){
			var ret=null;
			
			try { return document.createElement("<"+ntype+" name='"+nname+"'></"+ntype+">"); } catch(e) {}
			try {ret=document.createElement(ntype);ret.name=nname;} catch(e) {}
			return ret;
		},
		renderIntoInput: function(inputId, nval){
			var _el=document.getElementById(inputId);
			if(_el){
				if(nval){_el.value=nval;}
			}
		},
		setElementValue:function(inputEl,nval){
			inputEl.setAttribute("value",nval);
			inputEl.value=nval;
		},
		getDivInputsAsMap:function(divId){
			var ret={};
			var el=document.getElementById(divId);
			_private.collateFormTypeElements(el,ret);
			return ret;
		},
		setDivInputsFromMap:function(divId,map){
			var el=document.getElementById(divId);
			_private.setNodeValuesFromMap(el,map);
		},
		
		/* finds a child node of a given parent node
		 * according to child's tag name and a substring of child's id
		 * (makes it easier to deal with id's with appended instance numbers)
		 * if childTagName is null, searches all children
		 * boolean recursive - whether to search just immediate children (false)
		 * or entire depth of child trees (true)
		 */
		//note: atm, it'll return the first one it finds..
		//should i fix this to return an array of all or something?
		getChildNode: function(parent, childTagName, childIdSubstring, recursive){
			if(!childTagName){
				var nodes = parent.childNodes;
			} else {
				var nodes = parent.getElementsByTagName(childTagName);
			}
			if(nodes){
				for(var i=0; i<nodes.length; i++){
					if(nodes[i].id && nodes[i].id.match(childIdSubstring)){
						return nodes[i];
					}
					if(recursive){
						epiton.utils.Dom.getChildNode(nodes[i],childTagName,childIdSubstring,true);
					}
				}
			}
			return null;
		},
		
		//recursively append the count # to the id's of a node and all its children
		//store original id (baseId) and num (num) as members of the node
		//note that num is a string with an underscore, e.g. "_2" 
		setupInstanceIds: function(node, num){
			if(node.id){
				node.baseId = node.id;
				node.num = num;
				node.id += num;
			}
			var children = node.childNodes;
			if(children){
				for(var i=0; i<children.length; i++){
					epiton.utils.Dom.setupInstanceIds(children[i],num);
				}
			}
		},
		
		isInstance: function(node){
			return node.baseId && node.baseId!="" && node.num && node.num!="";
		},
		
		//a (somewhat dirty) fix for the problems that innerHTML causes (eg killing event handlers)
		//see: http://www.stefanjelner.de/item/208/
		convertHtmlStringToDom: function(htmlString){
			var containerNode = document.createElement("div");
			containerNode.innerHTML = htmlString;
			var docFrag = document.createDocumentFragment();
			for(var i=0; i<containerNode.childNodes.length; i++){
				docFrag.appendChild(containerNode.childNodes[i]);
			}
			return docFrag;
		},
		
		replaceInnerHtml: function(node, htmlString){
			//remove any existing children
			while(node.hasChildNodes()){
				node.removeChild(node.firstChild);
			}
			//put in new stuff
			node.appendChild(epiton.utils.Dom.convertHtmlStringToDom(htmlString));
		},
		
		//because IE doesn't implement node.textContent
		//see http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-textContent
		getNodeTextContent: function(node){
			if(node.innerText!==undefined){
				return node.innerText; //IE
			} else if(node.textContent!==undefined){
				return node.textContent; //FF and W3
			} else return null;
		},
		setNodeTextContent: function(node, text){
			if(node.innerText!==undefined){
				node.innerText = text; //IE
			} else if(node.textContent!==undefined){
				node.textContent = text; //FF and W3
			}
		},
		
		//errorMsg can be either a string or an array of strings
		setDefaultInputText:function(inputId, defaultText, errorMsg){
			var input = document.getElementById(inputId);
			//creating members for defaultText and errorMsg
			input.defaultText = defaultText;
			if(errorMsg){
				input.errorMsg = errorMsg;
			}
			input.value = defaultText; //fill field with default text initially
			if(input.type=="text"){
				input.onfocus = function(){epiton.utils.Dom.focusTextField(inputId);}
				input.onblur = function(){epiton.utils.Dom.blurTextField(inputId);}
			} else if(input.type=="password"){
				input.onfocus = function(){epiton.utils.Dom.focusPWfield(inputId);}
				input.onblur = function(){epiton.utils.Dom.blurPWfield(inputId);}
				epiton.utils.Dom.toggleBtwnPasswordandText(inputId, false); //change it to text
			}
		},
		
		setFieldToDefault: function(field){
			//field should be initialized with utils.Dom.setDefaultText and given defaultText
			//otherwise this method will do nothing to it
			if(field.defaultText){
				if(field.type=="password"){
					epiton.utils.Dom.toggleBtwnPasswordandText(field, false);
				}
				field.value = field.defaultText;
				//field.style.color = "black";
				epiton.utils.Dom.removeClass(field,"field_error");
			}
		},
		//errorIndex param is optional - use if errorMsg is array
		//field should be initialized with utils.Dom.setDefaultText and given an errorMsg 
		setFieldToError: function(field, errorIndex){
			if(field.type=="password"){
				field = epiton.utils.Dom.toggleBtwnPasswordandText(field.id, false);
			}
			epiton.utils.Dom.addClass(field,"field_error");
			if(field.errorMsg){
				if(errorIndex!==undefined && typeof field.errorMsg!="string"){
					field.value = field.errorMsg[errorIndex];
				} else if(typeof field.errorMsg == "string"){
					field.value = field.errorMsg;
				}
			}
		},
		fieldIsError: function(field){
			if(field.errorMsg){
				if(typeof field.errorMsg == "string"){
					return (field.value==field.errorMsg);
				} else { //it had better be an array
					for(var i=0; i<field.errorMsg.length; i++){
						if(field.value==field.errorMsg[i]){
							return true;
						}
					}
				}
			}
			return false;
		},
		
		
		blurAllFormFields: function(form){
			for(var i=0; i<form.length; i++){
				var n = form.elements[i];
				if(n.nodeName=="INPUT"){
					n.blur();
					/*
					if(n.type=="text"){
						epiton.utils.Dom.blurTextField(n.id);
					}else if(n.type=="password"){
						epiton.utils.Dom.blurPWfield(n.id);
					}
					*/
				}
			}
		},
		//resets all text or password input fields on a form to field's default text (if it has it)
		//removes any error message formatting
		//resets checkboxes according to defaultChecked attribute
		resetFormFields: function(form){
			for(var i=0; i<form.length; i++){
				var input = form.elements[i];
				if( (input.type=="text" || input.type=="password") && input.defaultText){
					//input.style.color = "black";
					epiton.utils.Dom.removeClass(input, "field_error");
					input.value = input.defaultText;
					if(input.type=="password"){
						epiton.utils.Dom.toggleBtwnPasswordandText(input.id, false);
					}
				} else if (input.type=="checkbox"){
					input.checked = input.defaultChecked;
				}
			}
		},
		
		//I'm not using this at the moment. but i'll leave it in case someday it's useful
		//only works if input elements have been manually assigned a "focused" member
		findFocusedInput: function(form){
			for(var i=0; i<form.length; i++){
				var n = form.elements[i];
				if(n.nodeName=="INPUT"){
					if(n.focused!==undefined){
						if(n.focused){
							return n;
						}
					}
				}
			}
			return null;
		},

		//returns ref to new node in dom tree
		toggleBtwnPasswordandText: function(inputId, isFocus){
			/*
			//type changing: works in FF except it causes the "cursor problem"
			var pw = document.getElementById(inputId);
			if(pw.type=="text")
			{
				try //ff
				{
					pw.setAttribute("type","password");
					return pw;
				}
				catch(e){}
			}
			else if(pw.type=="password")
			{
				try //ff
				{
					pw.setAttribute("type","text");
					return pw;
				}
				catch(e){}
			}
			*/
			//node replacement method - IE is good, FF needs this whole toggle method to be delayed to work
			var oldPW = document.getElementById(inputId);
			var form = oldPW.parentNode;
			var newField = document.createElement("input");
			if(oldPW.type=="text"){
				newField.type = "password";
			} else if(oldPW.type=="password"){
				newField.type = "text";
			}
			
			/*
			//this horribly breaks in IE :(
			//maybe cuz it has like 23094809234 attributes hah
			for(var a=0; a<oldPW.attributes.length; a++)
			{
				var att = oldPW.attributes[a];
				if(att.nodeName!="type")
				{	alert("att: " + att + "\n att.nodeName: " + att.nodeName + "\n att.nodeValue: " + att.nodeValue);
					newField.setAttribute(att.nodeName, att.nodeValue);
					//newField[att.nodeName] = att.nodeValue;
				}		
			}
			*/
			
			//copy other attributes
			newField.id = inputId;
			if(oldPW.name){newField.name = oldPW.name;}
			if(oldPW.size){newField.size = oldPW.size;}
			if(oldPW.defaultText){newField.defaultText = oldPW.defaultText;}
			if(oldPW.errorMsg){newField.errorMsg = oldPW.errorMsg;}
			//need to figure out how to copy the css, copy the class or something
			if(oldPW.className){newField.className = oldPW.className;}
			if(oldPW.style.width){newField.style.width = oldPW.style.width;}//note: cannot set entire style (style is a "getter" only)
			//copy focus and blur events
			if(oldPW.onfocus){newField.onfocus = oldPW.onfocus;}
			if(oldPW.onblur){newField.onblur = oldPW.onblur;}

			
			form.replaceChild(newField,oldPW);
			
			if(isFocus){
				newField.value = "";
				//IE needs BOTH of these focus calls to work
				newField.focus();
				document.getElementById(inputId).focus();
			}else{
				newField.value = oldPW.defaultText;
			}
			
			return newField;
		},
		
	//form field focus/blur functions (assuming defaultText) ---------------------------------------
		focusTextField: function(id)
		{
			var elem = document.getElementById(id);
			elem.focused = true; //set a flag
			epiton.utils.Dom.removeClass(elem, "field_error");
			if(elem.value==elem.defaultText || (epiton.utils.Dom.fieldIsError(elem)))
			{
				elem.value = "";
				//epiton.utils.Dom.removeClass(elem, "field_error");
			}
		},
		blurTextField: function(id)
		{
			var elem = document.getElementById(id);
			elem.focused = false;
			if(elem.value=="")
			{
				elem.value = elem.defaultText;
			}
		},
		
		blurPWfield: function(pw_id)
		{
			var pw = document.getElementById(pw_id);
			pw.focused = false;
			if(pw.value=="" && pw.type=="password")
			{
				setTimeout("if(document.getElementById('"+pw_id+"').type=='password'){epiton.utils.Dom.toggleBtwnPasswordandText('"+pw_id+"',false)}",10);
			}
		},

		focusPWfield: function(pw_id)
		{
			var pw = document.getElementById(pw_id);
			pw.focused = true;
			epiton.utils.Dom.removeClass(pw, "field_error");
			if((pw.value==pw.defaultText || (epiton.utils.Dom.fieldIsError(pw))) && pw.type=="text")
			{
				//epiton.utils.Dom.removeClass(pw, "field_error");
				epiton.utils.Dom.toggleBtwnPasswordandText(pw_id,true);
			}

		},
		
	//functions to help with changing element class attribute for css
		addClass: function(element, newClass){
			if(typeof newClass == "string" && !element.className.match(newClass)){
				if(element.className.length > 0){
					//element.className += " "; <-this gets stripped
					element.className += (" "+newClass);
				} else{
					element.className += newClass;
				}
			}
		},
		removeClass: function(element, removeMe){
			if(typeof removeMe == "string"){
				var start = element.className.indexOf(removeMe);
				if(start!=-1){ //if it's even there
					var end = start + removeMe.length - 1;
					//start building class string
					var classStr = "";
					//class names before removeMe
					if(start>0){
						classStr += element.className.substring(0,start);
					}
					//class names after removeMe
					if(end<(element.className.length-1)){
						classStr += element.className.substring(end+2); //no 2nd parameter -> extracts through end of string
					}
					//set it
					element.className = classStr;
				}
			}
		},
		replaceClass: function(element, oldClass, newClass){
			if(typeof oldClass == "string" && typeof newClass == "string"){
				if(!element.className.match(oldClass)){ //oldClass not there -> just add newClass
					epiton.utils.Dom.addClass(element, newClass);
				} else if(!element.className.match(newClass)){ //avoid duplication of newClass
					element.className = element.className.replace(oldClass, newClass);
				}
			}
		},
		
	//event helpers-----------------------------------------------
		//prevent event bubbling
		stopBubble: function(event){
			if(!event){ //ie
				window.event.cancelBubble = true;
			} else { //ff/w3
				event.stopPropagation();
			}
		},
		
		//adding and removing events (remember eventType is a string WITHOUT "on"!)
		//NOTE: since in IE you can only attach events to the bubbling phase,
		//for consistency there will be no capture/bubble boolean for these methods.
		//(addEventListener's and removeEventListener's last argument -> false means bubble)
		attachEvent: function(elem,eventType,handlerFunction){
			if(elem.addEventListener){ //w3
				elem.addEventListener(eventType,handlerFunction,false);
			} else if(elem.attachEvent){ //ie
				elem.attachEvent("on"+eventType,handlerFunction);
			}
		},
		detachEvent: function(elem,eventType,handlerFunction){
			if(elem.removeEventListener){ //w3
				elem.removeEventListener(eventType,handlerFunction,false);
			} else if(elem.detachEvent){ //ie
				elem.detachEvent("on"+eventType,handlerFunction);
			}
		}
		
	}
	return _public;
}();
//=================================================================================

epiton.utils.DebugLogger = function(){
	
	var _private = {
		
		isActive: false,
		
		active : ["ProxyCache"],
		
		window : null,
		
		reset : function(){
			delete _private.window;
			_private.window = null;
			window.onunload = null;
		}
		
	};
	
	var _public = {
		start : function(){
			
			if(_private.window===null){
				_private.window = window.open("","debug","width=500,height=500,menubar=no,toolbar=no,location=no,scrollbars=yes");
				_private.window.document.title = "Debug Logger :)";
				_private.window.onclose = _private.reset;
				
				var close = _private.window.document.createElement("div");
				epiton.utils.Dom.setNodeTextContent(close,"[close me]");
				close.style.cursor = "pointer";
				close.style.color = "orange";
				close.onclick = function(){
					_private.window.close();					
				}
				_private.window.document.body.appendChild(close);
				
				//window.onunload = function(){
				//	_private.window.close();
				//}
				
				window.onunload = function(){
					if(_private.window!==null && !_private.window.closed){
						var divider = _private.window.document.createElement("p");
						epiton.utils.Dom.setNodeTextContent(divider, "///// page refresh or change ////");
						divider.style.color = "red";
						_private.window.document.body.appendChild(divider);
					}
				}
				_private.isActive = true;
			}
		},
		log : function(senderName, message){
			var active = false;
			for(var i=0; i<_private.active.length; i++){
				if(_private.active[i]==senderName){
					active = true;
					break;
				}
			}
			if(active){
				if(_private.window!==null && !_private.window.closed){
					var p = _private.window.document.createElement("p");
					epiton.utils.Dom.setNodeTextContent(p, message);
					_private.window.document.body.appendChild(p);
					return true;
				}
			}
			return false;
		},
		activate : function(senderName){
			//if(_private.isActive){  //causing problems
				//avoid duplication
				var exists = false;
				for(var i=0; i<_private.active.length; i++){
					if(_private.active[i]==senderName){
						exists = true;
						break;
					}
				}
				if(!exists){
					_private.active.push(senderName);
				}
			//}
		}
	};
	
	return _public;
}();

//=================================================================================


epiton.utils.ProxyCache =
{	
	/*
	creates a ProxyCache instance attached to a single source file
	parameters:
	parent - reference to the obj to which ProxyCache instance belongs
	parentName - string to identify the parent
	filepath - path to source file
	selectedDivs - array of div ids or null; if not null, all content of source file except for those particular divs
		will be stripped (BEFORE storing to cache!!! ie you can't ever get to what you stripped off in this ProxyCache instance)
	init - boolean: true -> retrieves and caches source upon creation of instance;
		false -> retrieves and caches source upon first call to getSource
			(avoids unnecessary delay of retrieval upon instance creation)
	*/	

	instance: function(parent, parentName, filepath, selectedDivArray, init)
	{	//epiton.utils.DebugLogger.activate("ProxyCache");
		epiton.utils.DebugLogger.log("ProxyCache","---creating proxycache instance. parent is: "+parentName+", init is "+init);
		var _private = 
		{
			_parent: parent,
			_parentName: parentName,
			_filepath: filepath,
			
			_divArray: selectedDivArray,
			
			_dataCache: null,
			
			//avoid starting another call when we've already got one in the works
			_requestSent: false,
			
			_queue: [],
			
			_dequeueAll: function()
			{	epiton.utils.DebugLogger.log("ProxyCache","---dequeueAll");
				if(_private._queue.length > 0)
				{
					//"shift" way - too slow? but empties the array
					for(var item = _private._queue.shift(); item!=undefined; item = _private._queue.shift())
					{
						_private._handleItem(item);
					}
				}
			},
			//item holds: instance, instanceHandler, stripToDivId
			_handleItem: function(item)
			{	epiton.utils.DebugLogger.log("ProxyCache","---handleItem");
				var data = null;
				if(item.stripToDivId)
				{	epiton.utils.DebugLogger.log("ProxyCache","finding stripToDivId");
					//try: find div by trimming all
					if(_private._dataCache.isAll===true)
					{	epiton.utils.DebugLogger.log("ProxyCache","data isAll");
						data = _private._trim(_private._dataCache["all"], item.stripToDivId);
					}
					
					else
					{	epiton.utils.DebugLogger.log("ProxyCache","try: find div in map");
						//try: find div in map
						data = _private._dataCache[item.stripToDivId];
						if(!data)
						{	epiton.utils.DebugLogger.log("ProxyCache","searching within divs in map");
							//try: search within the divs stored
							for(var divId in _private._dataCache)
							{
								data = _private._trim(_private._dataCache[divId]);
								if(data!="")
								{	epiton.utils.DebugLogger.log("ProxyCache","found div within");
									break;
								}
							}
						}
					}
				}
				else
				{	epiton.utils.DebugLogger.log("ProxyCache","no strip");
					if(_private._dataCache.isAll===true)
					{	epiton.utils.DebugLogger.log("ProxyCache","returning all");
						data = _private._dataCache["all"];
					}
					else //concat everything
					{	epiton.utils.DebugLogger.log("ProxyCache","concat and returning all");
						var allText = "";
						for(var divId in _private._dataCache)
						{
							allText += _private._dataCache[divId];
						}
						data = allText;
					}
				}
				
				item.instanceHandler(item.instance, data);
			},
			
			//callback function passed to Ajax.getFileData function
			_storeData: function(req)
			{	epiton.utils.DebugLogger.log("ProxyCache","---storeData");
				if(!req||req.status!=200) return;
				
				var responseText=req.responseText;
				
				_private._dataCache = {};
				if(_private._divArray)
				{	epiton.utils.DebugLogger.log("ProxyCache","divArray -> caching via trim multiple");
					_private._trimMultiple(responseText, _private._divArray);
				}
				else
				{	epiton.utils.DebugLogger.log("ProxyCache","storing entire text to dataCache.all");
					_private._dataCache["isAll"] = true; //set a boolean to denote this state
					_private._dataCache["all"] = responseText;
				}
				
				//data is now cached, deal with all instances that got put into the queue
				if(!init)
				{
					_private._dequeueAll();
				}
				
			},
			
			_trimMultiple: function(text, divIdArray)
			{	epiton.utils.DebugLogger.log("ProxyCache","---trimMultiple");
				if(divIdArray.length>0)
				{
					for(var i=0; i<divIdArray.length; i++)
					{	epiton.utils.DebugLogger.log("ProxyCache","divIdArray[i] is "+divIdArray[i]);
						//note: if selectedDiv isn't found in the text, _trim returns ""
						//so that id will just be mapped to empty string in data cache
						_private._dataCache[divIdArray[i]] = _private._trim(text,divIdArray[i]);
					}
				}
				else
				{
					//no divs in array..which is silly...so don't do anything
				}
			},
			
			_trim: function(text, divId)
			{	epiton.utils.DebugLogger.log("ProxyCache","---trim - divId is "+divId);
				if(text.indexOf(divId)!=-1)
				{
					var start = -1;
					var end = -1;
					var splitArray = text.split("<");
					
					//DEBUG
					/*
					epiton.utils.DebugLogger.log("ProxyCache","BEGIN SPLIT ARRAY");
					for(var i=0; i<splitArray.length; i++)
					{
						epiton.utils.DebugLogger.log("ProxyCache","splitArray["+i+"]: "+splitArray[i]);
					}
					*/
					//---
					
					//need to ignore comments when parsing
					var inComment = false;
					
					//find beginning of div in question
					for(var i=0; i<splitArray.length; i++)
					{
						if(!inComment && splitArray[i].indexOf("!--")==0)
						{
							inComment = true;
						}
						if(!inComment)	
						{
							if(splitArray[i].indexOf("div")==0)
							{
								if(splitArray[i].match(divId)) //found it
								{
									start = i;
									break;
								}
							}
						}
						else
						{
							if(splitArray[i].match("-->")) //end of comment
							{
								inComment = false;
							}
						}
					}
					epiton.utils.DebugLogger.log("ProxyCache","start found as: "+i);
					//find end of our div, keeping in mind that there might be inner divs
					var innerCount = 0;
					inComment = false; //(reset)
					for(var i=start+1; i<splitArray.length; i++)
					{	
						if(!inComment && splitArray[i].indexOf("!--")==0)
						{
							inComment = true;
						}
						if(!inComment)
						{
							if(splitArray[i].indexOf("div")==0) //found inner div
							{
								innerCount++;
							}
							else if(splitArray[i].indexOf("/div")==0)
							{
								if(innerCount > 0) //found end of an inner div
								{
									innerCount--;
								}
								else if(innerCount==0) //found end of our div
								{
									end = i;
									epiton.utils.DebugLogger.log("ProxyCache","end found as: "+i);
									break;
								}
							}
						}
						else
						{
							if(splitArray[i].match("-->")) //end of comment
							{
								inComment = false;
							}
						}
					}

					//now that we know start and end, re-concatenate the parts
					var divText = "";
					for(var i=start; i<=end; i++)
					{
						divText += "<" + splitArray[i];
					}
					//epiton.utils.DebugLogger.log("ProxyCache","returning divText is: "+divText);
					return divText;
				}
				
				else
				{
					// if we got here, someone's looking for a div that's not in the source
					return "";
				}
			}
			
		};
		
		var _public =
		{	/* do i need this anymore?
			// ?!  callback only runs if ajax is needed!! not if it's cached!
			getSource: function(callback)
			{
				//if(!_private._dataCache)
				if(!_private._requestSent)
				{
					if(callback)
					{
						_private._callback = callback;
					}
					_private._requestSent = true;
					epiton.utils.Ajax.getFileData(_private._filepath,_private._storeData);
				}

				return _private._dataCache; //could be null if not set yet.
			},
			*/
			
			// NEW IDEA
			//instanceHandler(instance, data)
			enqueue: function(instance, instanceHandler, stripToDivId)
			{	epiton.utils.DebugLogger.log("ProxyCache","---enqueue: instance id is " + instance.id + ", stripToDivId is " + stripToDivId);
				if(!_private._requestSent)
				{	epiton.utils.DebugLogger.log("ProxyCache","sending ajax get");
					epiton.utils.Ajax.get(_private._filepath, _private._storeData);
					_private._requestSent = true;
				}
				var item = 
				{
					"instance" : instance,
					"instanceHandler" : instanceHandler,
					"stripToDivId" : stripToDivId //could be null
				}
				//if data not retrieved yet, enqueue it
				if(_private._dataCache===null)
				{	epiton.utils.DebugLogger.log("ProxyCache","data not retrieved yet, adding to queue");
					_private._queue.push(item);
				}
				//if we already have the data, run right away
				else
				{	epiton.utils.DebugLogger.log("ProxyCache","have data already, going directly to handle");
					_private._handleItem(item);
				}
			},
			
			getParent: function()
			{
				return _private._parent;
			}
			
		};
		
		if(init && !_private._requestSent)
		{	epiton.utils.DebugLogger.log("ProxyCache","init->sending ajax get");
			epiton.utils.Ajax.get(_private._filepath, _private._storeData);
			init = false;
			_private._requestSent = true;
		}
		
		return _public;
	} // close instance function - DON'T run it.

} // close ProxyCache

epiton.classloader.setLoaded("utils");
