/**
 * @author shane, nonken
 */
dojo.addOnLoad(function(){		
	dojo.query(".headLink").forEach(function(n){
		var linkto = dojo.attr(n,"id") + "Pane";
		
		var widget = new dojox.widget.FisheyeLite({
			properties: {
				height:42
			},
			easeOut:dojox.fx.easing.bounceOut,
			easeIn:dojox.fx.easing.linear,
			durationOut:700,
			durationIn: 100
		},n);
		
		var myTarget = dojo.query(".subtext",n)[0];
		if(myTarget){
			
		dojo.style(myTarget,{ opacity:"0", visibility:"visible" });			
			var _anim = null;
			dojo.connect(widget,"show",function(e){
				_anim && _anim.status && _anim.stop();
				_anim = dojo.fadeIn({ node: myTarget, duration:250 });
				_anim.play();
			});
			dojo.connect(widget,"hide",function(e){
				_anim && _anim.status && _anim.stop();
				_anim = dojo.fadeOut({ node: myTarget, duration:250 });
				_anim.play();
			});
		}
		
		dojo.connect(n,"onclick",function(e){	
			var key = linkto.replace(/LinkPane/, "");
			
			dijit.byId(key+'Menu').loadItem(key);
			
			dojo.featureExplorer.showPages(dijit.byId(key+'Menu').store, dijit.byId(key+'Menu').item, false);
		
			dijit.byId("feature-menu").resize();
			dijit.byId("feature-menu").selectChild(dijit.byId(linkto));
		});
	
	});
	
	dojo.query(".cp").instantiate(dijit.layout.ContentPane);			
	dojo.query("#feature-menu").forEach(function(n){
		new dojox.layout.RadioGroupSlideLeft({
			hasButtons:false
		},n).startup();
	});
	
	dojo.connect(dijit.byId('DojoMenu'), 'onClick', function(item) {
		dojo.featureExplorer.showPages(dijit.byId('DojoMenu').store, item);
	});
	
	dojo.connect(dijit.byId('DijitMenu'), 'onClick', function(item) {
		dojo.featureExplorer.showPages(dijit.byId('DijitMenu').store, item);
	});
	
	dojo.connect(dijit.byId('DojoxMenu'), 'onClick', function(item) {
		dojo.featureExplorer.showPages(dijit.byId('DojoxMenu').store, item);
	});
	
	dojo.featureExplorer.initUrl();
	dojo.featureExplorer.initSearchCombo();
});

dojo.declare("dojox.layout.RadioGroupSlideLeft",
	dojox.layout.RadioGroupSlide,
	{
	// summary: A Sliding Radio Group
	// description: 
	//		An extension on a stock RadioGroup widget, sliding the pane
	//		into view from being hidden. The entry direction is randomized 
	//		on each view
	//		

	// easing: dojo._Animation.easing
	//	A hook to override the default easing of the pane slides.
	easing: dojox.fx.easing.backOut,

	_positionChild: function(page){
         var rA = false;
         var rB = true;
         dojo.style(page.domNode, rA? "top" : "left", (rB ? "-" : "") + this._size[rA?"h":"w"]+"px");
     }
});

dojo.featureExplorer = {
	fullContent: "This demo is a standalone page. Click <a href='{1}' target='new'>here</a> to view it",
	_tabCounter: 0,
	baseUrl: null,
	isLoaded: false,
	
	onLoadFunctions: [],
	
	showPages: function(treeStore, item, isStateTransition) {
		dojo.featureExplorer.initStateControl(treeStore, item);
		dojo.featureExplorer.initialize();
		
		title = decodeURIComponent(treeStore.getValue(item, "name"));
		var title = title.split("_").join(" / ");
		var desc;
		var baseFileUrl = treeStore.getValue(item, "baseUrl");
		
		var pages = [];
		if(baseFileUrl){
			if(treeStore.getValue(item, "hasDesc")) {
				desc = {href:baseFileUrl + "txt"};
			}
			if(treeStore.getValue(item, "hasHtml")) {
				pages.push({
					label: "Demo",href:baseFileUrl + "html"
				});
				pages.push({
					label: "HTML",href:baseFileUrl + "html",escape:"xml"
				});
			} else if(treeStore.getValue(item, "hasFull")) {
				pages.push({
					label: "Demo",
					content:dojo.featureExplorer.fullContent.replace("{1}",
						"featureexplorer/" + baseFileUrl + "full.html")
				});
				pages.push({
					label: "HTML",href:baseFileUrl + "full.html",escape:"xml"
				});
			} else if(treeStore.getValue(item, "hasImages")) {
				pages.push({
					label: "Demos",href:baseFileUrl + "images.json", escape: "images"
				});
			}
			if(treeStore.getValue(item, "hasLinks")) {
				pages.push({
					label: "Links",href:baseFileUrl + "links.html"
				});
			}
			
			if(treeStore.getValue(item, "hasJs")) {
				pages.push({
					label: "JS",href:baseFileUrl + "js.txt",
					escape: "js"
				});
			}
		}
		
		var children = treeStore.getValues(item, "_children");
		
		if(pages.length == 0 && !desc){			
			return;
		}
		
		var pageData = [];
		var lastIsDesc = false;
		if(desc){
			pages.push(desc);
			lastIsDesc = true;
		}

		for(var i = 0; i < pages.length; i++) {
			pageData.push({label:pages[i].label, href:pages[i].href, 
							esc: pages[i].escape, content: pages[i].content});
		}
		
		dojo.featureExplorer._doShow(pageData, title, lastIsDesc);
		
		//window.location.href = dojo.featureExplorer.baseUrl + "#" + item.name;
	},
	
	_doShow: function(pageData, title, lastIsDesc){
		var numPages = pageData.length;
		var initNumPages = numPages;
		
		var titlePane = dijit.byId('featureTitlePane');
		if(lastIsDesc){
			numPages--;
			titlePane.setHref("featureexplorer/" + pageData[numPages].href);
		} else {
			titlePane.setContent("");
		}
		title = title ? title : "";
		
		dojo.byId("demoTitle").innerHTML = title;
		dojo.featureExplorer.cleanWidgets();
		dojo.featureExplorer.cleanConnects();
		dojo.featureExplorer.unsubscribeAll();
		var tabWidget = dijit.byId("featureTabs");
		
		tabWidget.selectedChildWidget = null;
		var widgetIds = {
			"Example":"tabView_" + dojo.featureExplorer._tabCounter,
			"JS":"tabJS_" + dojo.featureExplorer._tabCounter,
			"HTML":"tabHTML_" + dojo.featureExplorer._tabCounter,
			"Demos": "tabDemos" + dojo.featureExplorer._tabCounter
		};
		var widgetStyle = {
			"HTML": "htmlClass"
		};	
				
		for(var i = 0; i< numPages; i++){
			try{
			var newDiv =  dojo.doc.createElement('div');
			//newDiv.className = widgetStyle[pageData[i].label];
			
			var newTab = new dojox.layout.ContentPane({
				title: pageData[i].label,
				closable:false,
				id: widgetIds[pageData[i].label],
				refreshOnShow: false,
				adjustPaths: false,
				executeScripts: (pageData[i].label == "Demo"),
				renderStyles: (pageData[i].label == "Demo"),
				parseOnLoad: (!pageData[i].esc),
				href: pageData[i].href ? "featureexplorer/" + pageData[i].href : null
			},newDiv);
			
			if(!pageData[i].href && pageData[i].content){
				newTab.setContent(pageData[i].content);
			}
			
			if(pageData[i].esc){
				switch(pageData[i].esc){
					case "xml": dojo.featureExplorer.addXMLEscapeListener(newTab); break;
					case "js": dojo.featureExplorer.addJsEscapeListener(newTab); break;
					case "images": dojo.featureExplorer.addDemoImagesListener(newTab); break;
				}
			}

			tabWidget.addChild(newTab);
			newTab.startup();
			} catch(e) {
				console.log(e);
			}
		}
		
		if(initNumPages == 0){
			dojo.style(dijit.byId("featureTabs").domNode, "display", "none");
		} else {
			dojo.style(dijit.byId("featureTabs").domNode, "display", "block");
		}
		

		//Force the pane to update itself.  This gets around an issue
		//where some error may cause the tab the be positioned incorrectly.
		//dijit.byId("featureContent").layout();
	},
	
	highlightSubNodes: function(node) {
		//Get the keyword
		var key = dojo.query("span.keyword", node)[0];
		if(!key){return;}
		key = key.innerHTML;
		var textNode = node.nextSibling;
		if(!textNode || textNode.nodeType != 3){return;}//must be a test node

		var tagNames = [{name:"style", type:"css"}, {name:"script", type:"javascript"}];

		dojo.some(tagNames, function(item){
			if(item.name != key){return false;}

			var text = textNode.nodeValue;
			var tempDiv = document.createElement("div");
			dojo.addClass(tempDiv, item.type);
			dojo.style(tempDiv, "display", "none");
			dojo.body().appendChild(tempDiv);
			tempDiv.appendChild(document.createTextNode(text));

			dojox.highlight.init(tempDiv);

			var nextNode = textNode.nextSibling;
			while(tempDiv.firstChild){
				textNode.parentNode.insertBefore(tempDiv.firstChild, nextNode);
			}
			textNode.parentNode.removeChild(textNode);
			tempDiv.parentNode.removeChild(tempDiv);
			return true;
		});
	},
	
	addXMLEscapeListener: function(widget){
		var _this = this;
		var widgetContent;
		dojo.connect(widget, "_setContent", function(content){
		    widgetContent = content; 
		});
		widget.onLoadDeferred.addCallback(function(){
			dojo.featureExplorer.extractStyle(widgetContent);
			
			var escapedXML = dojo.featureExplorer.escapeXml(widgetContent).replace(/\t/g, "  ");
			
			widget.setContent("<pre><code>" + escapedXML + "</code></pre>");
			
			// Do not do code highlighting in IE, as it messes up the 
			// <PRE> formatting making the code unreadable
			if (!dojo.isIE) {
				dojox.highlight.init(widget.domNode.firstChild.firstChild);
				
				dojo.query("span.tag", widget.domNode.firstChild.firstChild).forEach(function(node){
					dojo.featureExplorer.highlightSubNodes(node);
				});
			}

			//Fire all the addOnLoad calls
			for(var i = 0; i < _this.onLoadFunctions.length; i++){
				_this.onLoadFunctions[i]();
			}
			_this.onLoadFunctions = [];
		});
    },
    	
	addDemoImagesListener: function(widget){
		var content;
		widget._setContent2 = widget._setContent;

		widget._setContent = function(str){
			if(str.indexOf("{") != 0){
				this._setContent2(str);
				return;
			}

			var data = dojo.fromJson(str);
			var store = new dojo.data.ItemFileReadStore({data:data});

			store.fetch({
				query:{},
				start:0,
				onComplete: function(items){
					var buf = [];

					dojo.forEach(items, function(item){
						buf.push("<div  class=\"explorer-feature-item\"  " +
						"\n\t\tonMouseOver=\"this.style.borderColor='#f8d582'; this.style.background='#fff';\"" +
						" \n\t\tonMouseOut=\"this.style.borderColor='#fff'; this.style.background='#fafafa';\">" +
						"\n\t<a href=\"#" + store.getValue(item, 'name') + "\" " +
						"onclick=\"dojo.featureExplorer.showEntry('" +
						store.getValue(item, 'name') +	"')\">" +
						"\n\t<img src=\"featureexplorer/" +	store.getValue(item, 'img') +	"\" width=\"76px\" height=\"75px\"/></a><br />" +
						store.getValue(item, 'label') + "</div>");
					});

					content = buf.join("");
				},
				onError: function(){
					console.log("Error getting json");
				}
			});
		};
		widget.onLoadDeferred.addCallback(function(){			
			widget.setContent(content);
		});
	},
	
	addJsEscapeListener: function(widget){
		widget.onLoadDeferred.addCallback(function(){
			widget.setContent("<pre>"+widget.domNode.innerHTML+"</pre>");
		});
	},
	
	escapeXml: function(/*string*/str){
		str = str.replace(/</gm, "&lt;").replace(/>/gm, "&gt;");
		return str; // string
	},
	
	cleanWidgets: function(widget) {
		var noDescendants = {
			"dijit.Declaration": true,
			"dojox.widget.Iterator": true
		};
		
		//Delete the tab panes from the tab widget cleanly.
		//Deleting them without using removeChild leaves some connects 
		//lying around that throw errors
		var tabWidget = dijit.byId("featureTabs");
		var tabKids = tabWidget.getChildren();
		if(tabKids){
			for(var i = 0; i < tabKids.length; i++){
				tabWidget.removeChild(tabKids[i]);
			}
		}
		
		var obj = dojo.featureExplorer._initWidgets;

		var h = dijit.registry._hash;

		var widgetsToDestroy = [];
		for (var x in h) {
			//If the widget is part of the framework, don't delete it.
			if(obj[x]){
				continue;
			}
			
			if (h[x].declaredClass == 'dojoc.sandbox.menu.AccordionMenuHeader' ||
				h[x].declaredClass == 'dojoc.sandbox.menu.AccordionMenuSubMenu' ||
				h[x].declaredClass == 'dojoc.sandbox.menu.AccordionMenuSubItem' ||
				h[x].id == 'searchCombo_popup') {
				continue;
			}
			
			widgetsToDestroy.push(h[x]);			
		}
		var widgetIds = [];
		
		
		for(var i = 0; i < widgetsToDestroy.length; i++){
			if(!h[widgetsToDestroy[i].id]){
				continue;
			}
			var widgetId;
			try{
				widgetId = widgetsToDestroy[i].id;
				
				widgetIds.push(widgetId);
				//There seems to be a bug when calling destroyDescendants on 
				//a dijit.Declaration. It seems to think that all widgets on the
				//page are it's children, so they're all destroyed.  So, 
				//don't call it!
				if (!noDescendants[widgetsToDestroy[i].declaredClass]) {
					widgetsToDestroy[i].destroyDescendants();
				}
			}catch(e){				
				console.log("Caught exception when destroying widget "+widgetId,e);
			}
			try {
				widgetsToDestroy[i].destroy();
			} catch (e) {
				console.log(e);
			} 
		}

		var node = dojo.featureExplorer._lastHeadElement;

		while(node.nextSibling) {
			node.parentNode.removeChild(node.nextSibling);
		}
		dojo.featureExplorer._tabCounter++;
	},
	
	cleanConnects: function(){
		var connects = dojo.featureExplorer._connects;
		var counter = 0;
		for(var x in connects){
			counter++;
			dojo.disconnect(connects[x]);
		}
		dojo.featureExplorer._connects = {};
	},
	
	initialize: function() {
		if(dojo.featureExplorer._initWidgets){
			return;
		}
		var obj = dojo.featureExplorer._initWidgets = {};
		for(var x in dijit.registry._hash){
			obj[x] = true;
		}
		
		dojo.featureExplorer._styleCache = {};
		
		//Remove the welcome message
		dijit.byId("featureTabs").containerNode.innerHTML = "";
		
		dojo.featureExplorer._openTopics = {};
		//put a listener on the subscribe method, and make sure that 
		//all events are unsubscribed when a demo is changed.
		dojo.connect(dojo, "subscribe", dojo.featureExplorer, "addSubscriber");
		dojo.connect(dojo, "unsubscribe", dojo.featureExplorer, "removeSubscriber");
		
		
		dojo._oldConnect = dojo.connect;
		var connects = dojo.featureExplorer._connects = {};
		var counter = 0;
		dojo.connect(dojo, "disconnect", function(conn){
			if(conn && (conn["_pos"] || conn["_pos"] === 0)){
				delete(connects[conn._pos]);
			}
		});		
		
		dojo.connect = function(a,b,c,d,e,f,g){
			var conn = dojo._oldConnect(a,b,c,d,e,f,g);
			connects[counter] = conn;
			conn._pos = counter++;
			return conn;
		};
		
		dojo.featureExplorer._lastHeadElement = dojo.featureExplorer._getHead().lastChild;
		
		//Override the addOnLoad to fire when the pane has loaded.
		dojo._oldAddOnLoad = dojo.addOnLoad;
		var _this = this;
		dojo.addOnLoad = function(fn){
			_this.onLoadFunctions.push(fn);
		};		
	},
	
	initUrl: function() {
		var url = window.location.href;
		var parts = url.split("#");
		dojo.featureExplorer.baseUrl = parts[0];
		var extension;
		
		if(parts.length > 1) {
			extension = parts[1];
			dojo.featureExplorer.showEntry(extension);
		}
	},
	
	addSubscriber: function(topic, listener) {
		//When a demo calls dojo.subscribe to subscribe to a topic, 
		//this function records that, and later this data is used
		//to ensure that all topics are unsubscribed from.
		var arr = dojo.featureExplorer._openTopics;
		if(!arr[topic]){
			arr[topic] = [];
		}
		arr[topic].push(listener);
	},
	
	removeSubscriber: function(topic, listener){
		//Removes a subscriber from the internal list, when the demo itself
		//calls dojo.unsubscribe
		var arr = dojo.featureExplorer._openTopics[topic];
		if(!arr){return;}
		for(var i = 0; i < arr.length; i++){
			if(arr[i] == listener){
				arr.splice(i, 1);
				break;
			}
		}
	},
	
	unsubscribeAll: function() {
		//Unsubscribes all functions from all topics that occurred
		//in a demo
		var allListeners = dojo.featureExplorer._openTopics;
		var arr;
		for (var topic in allListeners) {
			arr = allListeners[topic];
			for (var i = 0; i < arr.length; i++) {
				dojo.unsubscribe(topic, arr[i]);
			}
		}
		dojo.featureExplorer._openTopics = [];
	},
	
	updateTheme: function(){
		try{
			var combo = dijit.byId("themeCombo");
			var className = combo.getValue().toLowerCase();
			var oldClassName = className == "soria" ? "tundra" : "soria";
			var node = dijit.byId("featureTabs").domNode;
			dojo.removeClass(node, oldClassName);
			dojo.addClass(node, className);
			
			var width = combo.domNode.style.width.split("px")[0];
			setTimeout(function(){
				dojo.style( combo.domNode, "width", (width - 1) + "px");
				dojo.style( combo.domNode, "width", (width) + "px");
			}, 500);
			
			
		return true;
		} catch(e){
			console.log("updateTheme caught an exception",e);
		}
	},
	
	_getHead: function() {
		if(this._pageHead){
			return this._pageHead;
		}
		this._pageHead = dojo.byId("pageHead");
		return this._pageHead;
	},
	
	extractStyle: function(html){
		
		var minPosVal = -1, endTag;
		var tagBody, head = dojo.featureExplorer._getHead();
		var styleNode = dojo.byId("generatedStyles"), lastTagPos;
		
		var contentsBuffer = [];
		
		var pos = html.indexOf("<link ");
		var hrefPos, endHrefPos, newLink, href;
		
		while(pos > minPosVal) {
			endTag = html.indexOf(">", pos + 6);
			if(endTag < 0){
				console.log("Error: bad html, no closing > after pos "+pos);
				break;
			}
			tagBody = html.substring(pos + 6, endTag).split(" ").join("").split("\"").join("'");
			if(tagBody.indexOf("type='text/css'") > -1 || tagBody.indexOf("type='text\css'") > -1) {
				
				hrefPos = tagBody.indexOf("href='");
				if(hrefPos > -1){
					endHrefPos = tagBody.indexOf("'", hrefPos + 6);
					//newLink = document.createElement("link");
					//newLink.setAttribute("type","text/css");
					href = tagBody.substring(hrefPos + 6, endHrefPos);
					
					if (dojo.featureExplorer._styleCache[href]) {
						contentsBuffer.push(dojo.featureExplorer._styleCache[href]);
					}
					else {					
						dojo.xhrGet({
							url: href,
							sync: true,
							handleAs: "text",
							load: function(response, ioArgs){
								response = dojo.featureExplorer.fixStyleUrls(href, response);
								contentsBuffer.push(response);
								dojo.featureExplorer._styleCache[href]=response;
							},
							error: function() {
								console.log("Failed to download CSS file "+href);								
							}
						});
					}
				}
			}			
			
			minPosVal = pos +1;
			pos = html.indexOf("<link ", minPosVal);
		}
		if(contentsBuffer.length > 0) {
			styleNode.innerHTML = contentsBuffer.join("\n");
		}		
	},
	
	fixStyleUrls: function(href, contents){
		href = href.substring(0, href.lastIndexOf("/")+1);
		contents = contents.split("url(").join("url("+href);
		
		contents = contents.split("url("+href+"'").join("url('"+href);
		contents = contents.split("url("+href+"\"").join("url(\""+href);
		return contents;
	},
	
	showEntry: function(value, isStateTransition){
		//value = decodeURIComponent(value);
		dijit.byId("searchCombo").focusNode.value = decodeURIComponent(value.replace(/_/g , " / "));
				
		var nodeIds = value.split("_");
		var tree = dijit.byId(nodeIds[0]+"Menu");
		
		var totalPath ="";
		var treeNode, oldTreeNode;
		var connection;
		var nodeCounter = 0;

		function onEnd() {
			dojo.disconnect(connection);
			if (nodeCounter >= nodeIds.length) {
				atFinish();
			}
			else {
				openNext();
			}
		}

		function openNext(){
			var node = decodeURIComponent(nodeIds[nodeCounter]).replace(/ /g, "%20");
			
			totalPath += totalPath.length > 0 ? "_" + node : node;
			oldTreeNode = treeNode;
			if (nodeCounter == 0) {			
				widgetId = totalPath+"Menu";
				widgetPaneId = totalPath+"LinkPane";
			
				tree = previousTree = dijit.byId(widgetId);
				if (!tree) return;
				
				if (tree.isLoaded) {
					nodeCounter++;
			
					dijit.byId("feature-menu").selectChild(dijit.byId(widgetPaneId));
					tree.loadItem(totalPath);
					
					if (nodeCounter >= nodeIds.length) {
						atFinish();
					}
					else {
						openNext();
					}
				}
				else {
					var connect = dojo.connect(tree, "onComplete", function() {
						nodeCounter++;
						dojo.disconnect(connect);
			
						dijit.byId("feature-menu").selectChild(dijit.byId(widgetPaneId));
						tree.loadItem(totalPath);
						
						if (nodeCounter >= nodeIds.length) {
							atFinish();
						}
						else {
							openNext();
						}
					});
				}
			}
			else {
				tree = dijit.byId(totalPath);
				
				if (!tree.subMenu || tree.subMenu.isLoaded) {
					tree.loadItem(true);
				
					nodeCounter++;
					
					if (nodeCounter >= nodeIds.length) {
						atFinish();
					}
					else {
						openNext();
					}
				}
				else {
					var connect = dojo.connect(tree.subMenu, "onComplete", function() {
						dojo.disconnect(connect);
						tree.loadItem(true);
					
						nodeCounter++;
						
						if (nodeCounter >= nodeIds.length) {
							atFinish();
						}
						else {
							openNext();
						}
					});
				}
			}
			
					
			//console.log(totalPath);
			//console.log(tree);
			/*
			treeNode = tree._itemNodeMap[totalPath];
			if (!treeNode) {
				treeNode = oldTreeNode;
				atFinish();
				return;
			}
			if (!treeNode.isExpanded && treeNode.isExpandable) {
				//tree._expandNode(treeNode);
				//connection = dojo.connect(treeNode._wipeIn, "onEnd", onEnd);
			} else {
				openNext();
			}
			*/
		}
		function atFinish(){
			if (tree) {
				//tree.focusNode(treeNode);
				dojo.featureExplorer.showPages(navStore, tree.item, isStateTransition);
			}
		}
		openNext();
		
	},
	
	initSearchCombo: function() {
		//_getMenuLabelFromItem
		var combo = dijit.byId("searchCombo");
		combo._getMenuLabelFromItem = function(item){
			var val = decodeURIComponent(this.store.getValue(item, this.searchAttr));
			val = val.replace(/_/g , " / ");
			
			return {
				html: false, 
				label: val
			};
		}
		
		combo.onChange = function(value){
			dojo.featureExplorer.showEntry(value);
		}
	},
	
	initStateControl: function(store, item) {
		if(dojo.featureExplorer._stateInitialized){return;}
		dojo.featureExplorer._stateInitialized = true;

		ApplicationState = function(store, item){
			this._store = store;
			this._item = item;
			this.changeUrl = decodeURIComponent(item.name[0]);
		};

		dojo.extend(ApplicationState, {
			back: function(){
				this.showStateData();
			},
			forward: function(){
				this.showStateData();
			},
			showStateData: function(){
				dojo.featureExplorer.showEntry(this._store.getValue(this._item, "name"), true);
			}
		});

		function addState(store, item, isStateTransition){
			if(isStateTransition){return;}
			dojo.back.addToHistory(new ApplicationState(store, item));
		}
		var appState = new ApplicationState(store, item);
		dojo.back.setInitialState(appState);
		dojo.connect(dojo.featureExplorer, "showPages", addState);
	}
}

