UI = function() {
	this.components = {};
	this.registered = {};
	return this;
}
UI.prototype = {
	init: function(configs) {
		for(prop in configs) {
			if(!this.registered[prop]) continue;
			
			var config = configs[prop];
			
			var component = new UIComponent();
			
			if(config.tags) {
				var subscribers = component.getDomSubscribers(config.tags, config.key, config.value);
				if(subscribers && config.method) {
					component.applyConfigMethod(config.method);
				}
			}			
			this.components[prop] = component;
		}
	},
	register: function() {
		for(var i=0,len=arguments.length;i<len;i++) {
			this.registered[arguments[i]] = 1;
		}
	}
}

UIComponent = function() {
	this.members = [];
	return this;
}
UIComponent.prototype = {
	getDomSubscribers: function(tags, attr, value) {
		var len = tags.length-1,
			value = attrExp(value);
		do 
		{
			var name = tags[len];
			
			for(var i = 0; (t = document.getElementsByTagName(name)[i]); i++)
			{
				if(getAttrValue(t, attr).search(value) == -1) continue;
				this.members.push({id:resolveElemId(t)});
			}
		}
		while (len--);
		return this.members.length;
	},
	applyConfigMethod: function(method) {
		method = eval(method);
		var i = this.members.length-1;
		do {
			method.call(this, this.members[i]);
		} while(i--);
	}
};

/*/////////////////////////////////////POD//////////////////////////////////*/

function buildPodComponent(member)
{
	var handleContentAsText = (browser.ax);
	var stylefirst = (com.adobe.cssprofile.features.firstchild == false); 
	var id = member.id;
	var pod = makePodElem($(id), id+'-body', stylefirst, handleContentAsText);
	$(id).parentNode.replaceChild(pod.rootelem,$(id));
	
	function makePodElem(elem,bodyID,stylefirst,handleContentAsText)
	{
		var
		prevElem = null,
		skinElements = {
			'nw':{"elem":elem.cloneNode(false),"cssname":(elem.className.replace("dyn-pod","pod")+' nw')},
			'ne':{"elem":CachedElement.create('div'),"cssname":'ne'},
			'se':{"elem":CachedElement.create('div'),"cssname":'se'},
			'sw':{"elem":CachedElement.create('div'),"cssname":'sw'},
			'n':{"elem":CachedElement.create('div'),"cssname":'n'},
			's':{"elem":CachedElement.create('div'),"cssname":'s'},
			'w':{"elem":CachedElement.create('div'),"cssname":'w'},
			'e':{"elem":((handleContentAsText)? CachedElement.create('DIV') : elem.cloneNode(true)),"cssname":'pod-body e'}
		};
		
		if(!handleContentAsText)
		{
			for(var i=0,len=skinElements.e.elem.attributes.length;i<len;i++)
			{
				skinElements.e.elem.removeAttribute(skinElements.e.elem.attributes[i].nodeName);
			}
		}
		if(bodyID) 
		{
			skinElements.e.elem.setAttribute('id',bodyID);
		}	
		if(stylefirst)
		{
			var firsttag = getFirstTag(((handleContentAsText) ? elem : skinElements.e.elem));
			var str = (!firsttag.className) ? 'first-child' : firsttag.className+' first-child';
			firsttag.className = str;
			if(firsttag.nodeName == 'DL' || firsttag.nodeName == 'UL'  || firsttag.nodeName == 'OL')
			{
				var firstItem = getFirstTag(firsttag);
				var str = (!firstItem.className) ? 'first-child' : (firstItem.className+' first-child');
				firstItem.className = str;
			}
		}
		if(handleContentAsText) skinElements.e.elem.innerHTML = elem.innerHTML;
		
		for(prop in skinElements)
		{	 
		 skinElements[prop].elem.className =  skinElements[prop].cssname;
		 if(prevElem) prevElem.elem.appendChild(skinElements[prop].elem); //nest this element within the previous one
		 prevElem = skinElements[prop];
		}
		return { rootelem:skinElements.nw.elem, bodyelem:skinElements.e.elem };
	}
}

/*////////////////////////////////BALANCE ELEMENT HEIGHTS///////////////////////////*/

function balanceContentToPod()
{
	var 
	C1 = $('C1'),
	C1b = $('C1-body'),
	C2 = $('C2');
	
	if(C1&&C1b&&C2)
	{
		var 
		C1h = C1.offsetHeight,
		C1bh = C1b.offsetHeight,
		C2h = C2.offsetHeight,
		isTabContent;
		if (isTabContent=1) C1bh = C1bh-10;		
		if(C1h<C2h) {
			var h = ((C1bh-C1h)+C2h)+"px";
			if(com.adobe.cssprofile.features.layout && !com.adobe.cssprofile.isIE7) {
				C1b.style.height = h;
			}
			else {
				C1b.style.minHeight = h;
			}
		}
		return true;
	}	
	return false;
}

/*/////////////////////////////////////TREE LIST//////////////////////////////////*/

ToggleState = function(num)
{
	this.state = (num || 0);
	this.toggle = function()
	{
		this.state = (this.state) ? 0 : 1;
		return this.state;
	}
	return this;
}

function buildTreeList(member) {
	var styleObjects = {};
	var elem = $(member.id);
	//parse this treelist element
	for(var i=0,node; node = elem.childNodes[i]; i++) {	
	
		if(node.nodeType==3) continue; //ignore whitepspace
		
		switch(node.nodeName) {
			case "DT":
				//make sure there's a ID on this element
				dtID = resolveElemId(node);
				//initialize Array for all for this StyleObjects affected by this element
				styleObjects[dtID] = new Array();
				//make new style event for this element
				var styles = new StyleEvent(node);
				//add the dynamic styles to the event
				styles.add('on','off');
				//add the event object to the new array
				styleObjects[dtID].push(styles);
								
				// create active area and assign handler
				if(node.firstChild && (node.firstChild.nodeType==3)) {
					var cloneTXT = node.firstChild.cloneNode(false);
					var a = CachedElement.create('a');
					a.appendChild(cloneTXT);
					node.replaceChild(a, node.firstChild);
				} else {
					var a = node.firstChild;
				}
					
				//refer elem prop to Style Events Array
				a.styles = styleObjects[dtID];
				
				var initnum = (styles.styles['on']) ? 1 : 0;
				//append state manager
				a.togglestate = new ToggleState(initnum);
				a.onclick = function() {
					var i;
					this.togglestate.toggle();
					switch(this.togglestate.state)
					{
						case 0:
							for(var i=0;i<this.styles.length;i++) {
								this.styles[i].toggle('off','on');
							}
							break;
						case 1:
							for(var i=0;i<this.styles.length;i++) {
								this.styles[i].toggle('on','off');
							}
							break;
					}
					return void(0);
				}
					
				
			break;
			case "DD":
				var ddID = resolveElemId(node);
				//new style event object for this element
				var styles = new StyleEvent(node);
				//add the new event to the array created above
				styleObjects[dtID].push(styles);
			break;
		}	
	}
	
	elem.className = elem.className.replace("dyn-","");
	
	member.styleObjects = styleObjects;
}

/*/////////////////////////////////////TREE EXPLODE//////////////////////////////////*/

function makeTreeExplode(member) {	
	var elem = $(member.id);
	
	var attrIds = getAttributesAtMarker(elem.rel,'dyn-','explodetree');
	
	if(!attrIds.length) return false;
	
	var trees = com.adobe.ui.components.trees.members;
	
	var treeobjs = [];
	for(var i=0,len=trees.length;i<len;i++)
	{
		var tree = trees[i];
		
		for(var id=0,idlen=attrIds.length;id<idlen;id++)
		{
			attrId = attrIds[id];
			if(tree.id != attrId) continue;
			for(prop in tree.styleObjects)
			{
				treeobjs = treeobjs.concat(tree.styleObjects[prop]);
			}
			attrIds.splice(id,1);
		}
	}
	var gg = new ToggleLinkText();
	var itxt = gg.init(elem,1);
	elem.gg = gg;
	
	
	if(!elem.firstChild)
	{
		elem.appendChild(document.createTextNode(itxt));
	}
	
	elem.styles = treeobjs;
	elem.style.cursor = "pointer";
	elem.onclick = function()
	{
		this.firstChild.nodeValue = this.gg.run();
		var s = (this.gg.state) ? ['on','off'] : ['off','on'];
		for(var i=0,len=this.styles.length;i<len;i++)
		{
			var style = this.styles[i];
			style.toggle(s[0],s[1]);
		}
	};
	elem.firstChild.nodeValue = elem.gg.run();
	return;
};

/*////////////TOGGLE LINK////////////*/

ToggleLinkText = function()
{
	this.state;
	this.txt;
	this.init = function(a,state)
	{
		var text = (a.text || ""); 
		this.state = (state || 0);
		this.txt = [(a.title+text),(a.rev+text)];
		a.removeAttribute('rev');
		a.removeAttribute('title');
		return this.txt[this.state];
	}
	this.run = function()
	{
		this.state = (this.state) ? 0 : 1;
		return this.txt[this.state];
	}
	return this;
}

/*////////////TABS///////////*/

function buildTabSection(member) {
	var queryPrefix = "tab:";
	
	var newtab, nontab,
	elem = $(member.id),
	nav = CachedElement.create('ul'),
	navstyle = (elem.className.indexOf('microtab') > -1) ? "microtab menu compact" : "tab menu compact",
	tabManager = new TabManager(),
	subtags = elem.childNodes;
				
	nav.setAttribute('class', navstyle); //new nav list
	if(!nav.className) nav.className = navstyle; //for IE

	for(var s=0,klen = subtags.length;s<klen;s++)
	{
		var kid=subtags[s];
		
		if(!kid || (kid.nodeType != 1)) continue; //garbage nodes or non-tags
				
		switch(kid.className)
		{
			case "tabtitle":
				var titleId = resolveElemId(kid); //resolve element ID
				var contentDIVtitle = kid.firstChild; //get text from title element
				var menuItem = CachedElement.create('li'); //new list item
				var menuLink = CachedElement.create('a'); //new link
			
				//All this has to happen for tab manager to work on this element
				menuItem.setAttribute('id', titleId); //resolve element ID for tab manager
				newtab = tabManager.addTab( titleId, 0 ); //add menuItem ID to tab manager
				var referencestyle = new StyleEvent(menuItem); //manage element clasname changes
				referencestyle.add('on','off'); //initialize dynamic clasnames
				tabManager.styleObjects[titleId] = referencestyle; //add style object to tab manager 

				menuLink['tabkey'] = titleId; //hook into for tab manager
				menuLink.tab = tabManager; //to resolve scope issues appending reference to DOM element
				menuLink.onclick = function() {
					//check for window query object
					var winUpdate = false;
					var total = "tab:"+this.tabkey;
					if (window.location.search.indexOf('tab:') > -1) 
					{
						var a = 'tab:'+this.tab.states.current+'=1';
						var b = 'tab:'+this.tabkey+'=1';
						winUpdate = updateUrlQuery(a,b);
					}
					if(!winUpdate) 
					{
						this.tab.setState(this.tabkey);
					}
				}
				
				menuLink.appendChild(contentDIVtitle); //append title to link
				menuItem.appendChild(menuLink); //append link to item
				nav.appendChild(menuItem); //append item to nav
				break;
			case "tabcontent":
				var contentId = resolveElemId(kid); //resolve element ID
				tabManager.bindContent(newtab,contentId); //bind content ID to tab manager referer key
				var contentstyle = new StyleEvent(kid); //manage element clasname changes
				contentstyle.add('hide'); //initialize dynamic clasnames
				tabManager.styleObjects[contentId] = contentstyle; //add style object to tab manager				
				break;
		}
	}
	elem.parentNode.insertBefore(nav, elem);
	elem.className = "";
			
	var pick = 0; //set the pick to the first item
			
		for (var z=0; z<tabManager.states.items.length; z++) {
			var kd = tabManager.states.items[z].key;
			var urlQuery = com.deconcept.util.getRequestParameter(queryPrefix+kd);
			if (urlQuery) pick = z;
	}
	if(!tabManager.states.items.length) {
		return;
	}
	var pickID = tabManager.states.items[pick].key;
	var isTabContent=1;
	balanceContentToPod();
	tabManager.setState(pickID);
	
	this[member.id] = tabManager; //add new tabmanager to the parent component. Pretty weird.
}

TabManager = function()
{
	this.styleObjects = {};
	this.contents = {};
	this.states = new StateSwitch();
	this.setState = function(id)
	{
		var newstate = this.states.setCurrent(id);
		if(newstate)
		{
			this.setStyles(this.states.items);
		}
	}
	this.addTab = function(key, value)
	{
		this.contents[key] = [];
		var result = this.states.addItem(key,value);
		return result;
	}
	this.bindContent = function(obj, contentId)
	{
		if(!this.contents[obj.key]) return null; //this key does not have a referer
		this.contents[obj.key].push(contentId); //attach the referers key to this object to point to contentID
		return this.contents[obj.key].length;
	}
	
	this.setStyles = function(elements)
	{
		for(var i=0,element; element = elements[i]; i++)
		{
			switch(element.value)
			{
				case 0: 
					this.styleObjects[element.key].toggle('off','on');
					for(var c=0,content; content=this.contents[element.key][c]; c++)
					{
						this.styleObjects[content].enable('hide');
					}
				break;
				case 1: 
					this.styleObjects[element.key].toggle('on','off');
					for(var c=0,content; content=this.contents[element.key][c]; c++)
					{
						this.styleObjects[content].disable('hide');
					}
				break;
			}
		}
	}

}

///////////////////////////DYNAMIC SWITCH BEHAVIORS//////////////////////////////

StateSwitch = function()
{
	this.current = '';
	this.items = [];
	
	this.addItem = function(id, value)
	{
		var obj = {'key':id, 'value':value};
		this.items.push(obj);
		return obj;
	}
	
	this.setCurrent = function(id)
	{
		if(this.current == id) return false;
		
		var len = this.items.length;
		for(var i=0;i<len;i++)
		{
			this.items[i].value = (this.items[i].key == id) ? 1 : 0;
		}
		this.current = id;
		return true;
	}
	
	return this;
}

/*///////////////////////// WINDOW HANDING ////////////////////////////////////*/

updateUrlQuery = function(currStr,newStr)
{
	var tabQueryString = window.location.toString();
	if(tabQueryString.indexOf(newStr) > -1) return false; //requested query update is already here
	if(tabQueryString.indexOf(currStr) == -1) return false; //this query was not loaded so it doesn't need managing
	
	var tabQueryString = tabQueryString.replace(window.location.hash,'');
	tabQueryString = tabQueryString.replace(currStr,newStr);

	return window.location = tabQueryString;
}

TabLocation = function()
{
	this.location = window.location.toString();
	this.tabsyntax = ['tab:','=1'];
	this.initLookup = function(obj)
	{
		this.lookup = {};
		for(prop in obj)
		{
			var pos = prop.indexOf(this.tabsyntax[0]);
			if(pos == -1) continue;
			var n = prop.substring(pos+this.tabsyntax[0].length);
			var v = obj[prop];
			this.lookup[n]=v;
		}
		return true;
	}
	
	this.update = function(currStr,newStr)
	{
		if(this.location.indexOf(newStr) > -1) return false; //requested query update is already here
		if(this.location.indexOf(currStr) == -1) return false; //this query was not loaded so it doesn't need managing
		
		this.location = this.location.replace(window.location.hash,'');
		this.location = this.location.replace(currStr,newStr);
		return window.location = this.location;
	}
}

function explodeQueryString(str,div,assign)
{
	var output={};
	var pairs = str.split(div);
	for(var i=0;i<pairs.length;i++)
	{
		var pos = pairs[i].indexOf(assign);
		if(pos == -1) continue;
		var n = pairs[i].substring(0,pos);
		var v = pairs[i].substring(pos+1);
		output[n] = v;
	}	
	return output;
}

var winquery = window.location.search;
if(winquery.length) 
{
	var pos = winquery.indexOf('tab:');
	if(pos > -1)
	{
		var winquery = winquery.substring(1);
		var queryObject = explodeQueryString(winquery,'&','=');
		this['tabparams'] = new TabLocation();
		this.tabparams.initLookup(queryObject);
	}
}

/*///////////////////////// TREE WALKING ////////////////////////////////////*/

function contentBefore()
{
	var str = arguments[0];	
	if(arguments[1])
	{
		obj = spaceSpan(str);
		obj.className = "space";
		obj.style.position = "relative";
		obj.style.right = arguments[1];
	}
	else
	{
	 	obj = document.createTextNode(str);
	}
	this.insertBefore(obj,this.firstChild);
	return;
}
function contentAfter()
{
	var str = arguments[0];
	var obj;
	if(arguments[1])
	{
		obj = spaceSpan(str);
		obj.className = "space";
		obj.style.position = "relative";
		obj.style.left = arguments[1];
	}
	else
	{
	 	obj = document.createTextNode(str);
	}
	this.appendChild(obj);
	return;
}
function spaceSpan(str)
{
	var span = CachedElement.create('span');
	span.appendChild(document.createTextNode(str));
	return span;
}
function adjacent()
{
	this.shift();
	return this;
}
function last()
{
	return this[this.length-1];
}
function marker(method,mark,marg)
{
	if(isArray(this))
	{
		for(var i = 0,len=this.length;i<len;i++)
		{
			method.apply(this[i],[mark,marg]);
		}
	}
	else if(isObject(this))
	{
		method.apply(this,[mark,marg]);
	}
}

Children = function()
{
	this.method;
	this.setMethod = function(a)
	{
		return (document.body.children) ? 'children' : 'childNodes'; //dynamic lists in W3 and IE
	}
	this.checkName = function(n,v)
	{
		return n.nodeName == v;
	}
	this.checkNone = function()
	{
		return true;
	}
}

Children.prototype._all = function(root,name)
{
	if(!this.method) this.method = this.setMethod();
	name = (name || "");
	var o = new Array();
	var checkName = (name) ? this.checkName : this.checkNone;
	
	if(isTag(root))
	{
		for(var i=0; (node=root[this.method][i]); i++)
		{
			if(isTag(node) && checkName(node,name)) o.push(node);
		}
	}
	else if(isArray(root) || isNodeList(root))
	{
		var len=root.length-1;
		do
		{
			if(isTag(root[len]))
			{
				var n = this._all.apply(this,[root[len], name]);
				o = o.concat(n.reverse());
			} 
		}
		while (len--);
	}
	return o;
}
Children.prototype.first = function(root, name)
{
	if(!this.method) this.method = this.setMethod();
	name = (name || "");
	var checkName = (name) ? this.checkName : this.checkNone;
	if(isTag(root))
	{
		if(this.method=="children")
		{
			return (checkName(root.children[0],name)) ? root.children[0] : null;
		}
		else if(this.method=="childNodes")
		{
 			for(var i=0; (node=root.childNodes[i]); i++)
			{
				if(isTag(node) && checkName(node,name))
				{
					return node;
				}
			}
		}
	}
	return null;
}
Children.prototype.last = function(root,name)
{
	if(!this.method) this.method = this.setMethod();
	name = (name || "");
	var checkName = (name) ? this.checkName : this.checkNone;
	if(isTag(root))
	{
		if(this.method=="children")
		{
			var last = root.children[root.children.length-1];
			return (checkName(last,name)) ? last : null;
		}
		else if(this.method=="childNodes")
		{
 			for(var i=root.childNodes.length-1; (node=root.childNodes[i]); i--)
			{
				if(isTag(node) && checkName(node,name))
				{
					return node;
				}
			}
		}
	}
}

children = new Children();

/*/////////////////////////////////////AUTO INITIALIZE HERE//////////////////////////////////*/

com.adobe.ui = new UI();
registerOnReady( function() { 
	com.adobe.ui.init({
		"pods": { 
			id:'root', 
			key: 'className', 
			value:'dyn-pod', 
			tags: ['div'], 
			method: "buildPodComponent"
		},
		"tabs": { 
			id: 'root', 
			key: 'className', 
			value:'dyn-tabsection', 
			tags: ['div'], 
			method: "buildTabSection"
		},
		"trees": { 
			id: 'root', 
			key: 'className', 
			value:'dyn-treelist', 
			tags: ['dl'], 
			method: "buildTreeList"
		},
		"explodes": { 
			id: 'root', 
			key: 'rel', 
			value:'dyn-explodetree',
			tags: ['a'], 
			method: "makeTreeExplode"
		}
	});
});

registerOnReady(writeFOArr);

registerOnReady(function() {
						 
	balanceContentToPod();
	
	var af = com.adobe.cssprofile.features.after;
	var lc = com.adobe.cssprofile.features.lastchild;
	var dp = $('depthpath');
		
	if(dp && !af || dp && !lc) {
		var paths = children._all(dp,'LI');
		if (paths.length != 0) {					
			paths[paths.length-1].className = "last-child";
			var pathsA = children._all(paths,'A');
			marker.apply(pathsA,[contentAfter,"/","1ex"]);
			
		}
	}
	if(com.adobe.cssprofile.features.layout) {
		for(var i = 0; (s = document.getElementsByTagName("select")[i]); i++) {
			var e=getOverlapId(resolveElemId(s));
			if(!e) continue;
			
			var dom = $(e);
			
			if(dom.masks) {
				dom.masks.push(s);
				continue;
			}
			else
			{
				dom.masks = new Array(s);
				dom.onmouseover = function() {
					var i = this.masks.length-1;
					if(i<0) return;
					do {
						this.masks[i].style.visibility = "hidden";
					} while(i--);
				}
				dom.onmouseout = function() {
					var i = this.masks.length-1;
					if(i<0) return;
					do {
						this.masks[i].style.visibility = "visible";
					} while(i--);
				}
			}
		}
	}					 
});

