/*******************************************************************************
 * Copyright (c) 2007, 2008 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
dojo.provide("org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator");
dojo.require("dijit.Menu");
dojo.require("dijit.Tree");
dojo.require("dijit.TitlePane");
dojo.require("dijit.layout.ContentPane");
dojo.require("org.eclipse.cosmos.provisional.dr.ps.components.data.LazyLoadStore");
dojo.require("org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryDialog");
dojo.requireLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget");

function publishDelayEvent(){
}

dojo.declare(
	// class
	"org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator",

	// superclass	
	[dijit.Tree],
	
	// member variables/functions
	{
		//summary: This class provides a tree widget that gets its content from a url 
		//description: This widget has several key features:
		//              1.  Displays icons next to children nodes
		//              2.  Lazy loads nodes
		//              3.  Constructs menu options that are dynamically created.
		//              4.  Able to add and remove nodes to the tree
		//              5.  When a node is selected the contents of the node is published to a list of topics
		//initQueryHandler: String
		//   provides the url that will get the tree model that the tree renders
	    initQueryHandler: null,
	    //progressNode: DOMElement
	    //  html node that shows the onload progress indicator
	    progressNode: null,
	    //progressDescription:String
	    //  text string that contains the progress description
	    progressDescription: null,
	    //rollerImagePath: String
	    //  url path to the progress indicator icon
		rollerImagePath:dojo.moduleUrl("dijit","themes/tundra/images/treeExpand_loading.gif").uri,
		//publish: Array of Strings
		//  a list of topics that will be published to when the user selects a node
		publish:[],
		nodeHighlighted: false,
		progressCreated : false,
		initQuery: true,
		create: function(params, srcNodeRef) {
		//summary: the create method for this widget
		//description: This method will create a lazy load store based on the url passed into the params.initQueryhandler
			var oldMenu= dijit.byId(this.id+"_menu");
			if (oldMenu)
				oldMenu.destroy();
			if ((params.contextMap) && (params.contextMap.initQueryHandler)){
				params.initQueryHandler = params.contextMap.initQueryHandler;
			}			
			if (params.initQueryHandler != null){
				if ((params.contextMap) && (params.contextMap.object)){
					params.initQueryHandler = params.initQueryHandler+"&id="+params.contextMap.object;
				}
				params.store=new org.eclipse.cosmos.provisional.dr.ps.components.data.LazyLoadStore({url:params.initQueryHandler});
				dojo.connect(params.store, "responseError", this, "destroyProgress");
				params.store.UIContext = params.UIContext;														
			}
			dojo.connect("publishDelayEvent", this, "highlightNode");
			org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator.superclass.create.apply(this, arguments);
		},
		getIconClass: function(/*dojo.data.Item*/ item){
			// summary: user overridable function to return CSS class name to display icon
		    if ((item) && (item.nodeClass)){
				initParam = this.dataMap[item.nodeClass];
				if (initParam){
					return initParam.icon;
					}
			}			
		},		
		postMixInProperties: function(){
			//summary: postMixinProperties method for this widget
			//description: initializes the menu for the tree
			var cell = document.createElement("ul");
			cell.setAttribute("style", "display:none;");
			cell.setAttribute("id", this.id+"_menu");
			this.parentWidget.domNode.appendChild(cell);
			this.menu = new dijit.Menu({},cell);	
			org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator.superclass.postMixInProperties.apply(this, arguments);
		},
		destroy: function(){
			//summary: destroy method for this widget
			this.menu.destroy();
			org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator.superclass.destroy.apply(this, arguments);
		},		
		createContextMenu: function(e){
			//summary: constructs the menu based on the node that was selected
			var menu = this.menu;
			this.menu.getChildren().forEach(function(i){menu.removeChild(i);});
			var tn = dijit.getEnclosingWidget(e.target);
			var itemMap = this.dataMap[tn.item.nodeClass];
			var contextMenuFactory = null;
			if ((itemMap) && (itemMap.menuType)){
				if (dojo.isArray(itemMap.menuType)){
					for (i=0;i < itemMap.menuType.length;i++){
						contextMenuFactory = this.UIContext.createObject(itemMap.menuType[i]);
						contextMenuFactory.nodeFactory = this.nodeFactory;
						contextMenuFactory.UIContext = this.UIContext;
						contextMenuFactory.sourceObject=this;		
						contextMenuFactory.createContextMenu(this.menu,tn,tn.item.nodeClass, i);
					}
				}
				else{
					contextMenuFactory = this.UIContext.createObject(itemMap.menuType);
					contextMenuFactory.nodeFactory = this.nodeFactory;
					contextMenuFactory.UIContext = this.UIContext;
					contextMenuFactory.sourceObject=this;		
					contextMenuFactory.createContextMenu(this.menu,tn,tn.item.nodeClass, i);
				}
			}
			
		},
	    treeHandler: function(/*Object*/message){
			//summary: This method is called when the user selects a node
			//description: The message parameter contains the node that was selected.  The message parameter is cloned and published to 
			//  topics specified by the the publish memeber variable of this class.
		    if (message.event != 'execute') {
    		  return;
  			}
		    this.publishItemMessage(message.node.item, message.mixinParams);
	    },
	    publishItemMessage: function(/*Object*/item, /*Object*/mixinParams){
	    	//don't publish if the node is a folder
			if ((typeof(this.publish) != 'undefined') && ((!item.isFolder) || (item.isFolder[0] != true))){
				for (i=0;i < this.publish.length;i++){
				 	    //lets clone the information we're going to send to another widget since we don't want the other
				 	    //widget modifying our content
						var cloneMap = new Object();
				 	    dojo.mixin(cloneMap,item);
				 	    //let tag the data we're going to send so that the consumer of this data knows where the data came from
				 	    if (cloneMap.viewClass){
				 	    	cloneMap.nodeClass = this.attachPoint + " " +cloneMap.viewClass;
				 	    } else {
				 	    	cloneMap.nodeClass = this.attachPoint + " " +cloneMap.nodeClass;
				 	    }
				 	    if (mixinParams){
					 	    dojo.mixin(cloneMap, mixinParams);
				 	    }
				 	    this.addToMessage(cloneMap);
						dojo.publish(this.publish[i], [{contextMap:cloneMap}]);
					}
			}
	    	
	    },
	    addToMessage: function(message){	    	
	    	//summary: convenient method that is called before publishing the message when a user selects a node
	    	//description: this method can be ovveridden to add additional properties to the message before publishing
	    },
		mayHaveChildren: function(/*dojo.data.Item*/ item){
			var initParam = this.dataMap[item.nodeClass];
			var hasChildren = false;			
			//check to see if this node has an expand query
			if ((initParam) && (typeof(initParam['expandQuery'])!='undefined')){
				//append query to item so that we don't have to make lookup again
				item.expandQuery = initParam.expandQuery;
				hasChildren = true;
			}
			if (hasChildren == false){
				hasChildren = org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator.superclass.mayHaveChildren.apply(this, arguments);
			}
			return hasChildren;
	
		},
		makeNodeFolder: function(el){
			//summary: displays an icon next to nodes that have been added to the tree.
		    if (el.item.nodeClass){
				initParam = this.dataMap[el.item.nodeClass];			
				if (initParam){
						//check to see if this node has an expand query
						if (typeof(initParam['expandQuery'])!='undefined'){
							el.item.isExpandable = true;
							}
				}
		    }
			dojo.connect(el,"addChild", this, "makeNodeFolder");
		},	    
		postCreate: function(){
			//summary: postCreate method for this widget
			//description: sets up the pop-up menu and handlers used to manage the tree nodes
			// when we right-click anywhere on the tree, make sure we open the menu		  	
			this.menu.bindDomNode(this.domNode);				
			dojo.connect(this.menu, "_openMyself", this, this.createContextMenu);
			//subscribe to node selection topic
		  	dojo.subscribe(this.id, this, this.treeHandler);
		  	dojo.connect(this, "addChild", this, this.makeNodeFolder);
		  	if (this.params){
			  	this.params.mayHaveChildren = this.mayHaveChildren;
			  	this.params.getItemChildren = this.getItemChildren;
		  	}
		  	//post create will try to load the top level node.
		  	//we should open a progress bar to indicate that the widget is being intialized.
		  	this.inherited("postCreate", arguments);
			this.model.root.children=[];
		},
		createProgress:function(){
			//summary: creates the progress node
			if ((this.progressDescription != null) && (this.progressCreated == false)){
				this.progressNode = document.createElement('div');
				var progressText = document.createElement('span');
				progressText.setAttribute("style", "padding-left:5px");
				progressText.appendChild(document.createTextNode(this.progressDescription));
				var img = document.createElement('img');
				img.setAttribute("src", this.rollerImagePath);
				this.progressNode.appendChild(img);
				this.progressNode.appendChild(progressText);
				this.domNode.appendChild(this.progressNode);
				this.progressCreated = true;
			}
			
		},
		_expandNode: function(/*_TreeNode*/ node){
			this.inherited(arguments);
			if (node == this.rootNode){
				if (node.state = "LOADED")
					this.unmarkProcessing();
			}
		},
		unmarkProcessing: function(){
			//summary: this function is called after loading the model into the tree.  The progress indicator is destroyed.
			this.destroyProgress();
		},
		destroyProgress: function(keyArgs){
			//summary: destroys the progress indicator node.
			if (this.progressNode){
				this.domNode.removeChild(this.progressNode);
			}
		},		
		addTreeNode:function(/*dojo.data.Item[]*/newItem, /*dojo.data.Item*/parent, /*boolean*/expand){
			// summary: Adds an item to the tree.  
			// description: This method takes in a list of items that will be added to a parent item.  
			//              The newItem contains an array of items that will be added to the item defined by the parent parameter.
			//              If the expand parameter is set to true the parent item will be expanded other the parent item will be collapsed.
			if (typeof(expand) == 'undefined'){
				expand = false;
			}
			if (typeof(parent) == 'undefined')
				parent = this.treeNode.item;
			try{
				if (dojo.isArray(newItem)) {
					for (var x=0; x < newItem.length; x++){
						this.addTreeNode(newItem[x], parent);			   
					}
				}
				else{
					childObject = this.store.newItem(newItem, {parent:parent,attribute:'children'});
					//for some reason dojo1.1 requires the attributes to be arrays.
					childObject.parentItem = [parent];
					//expand parent node	
					if (expand){
						var parentNode = this._itemNodeMap[this.store.getIdentity(childObject.parentItem[0] )];
						this._expandNode(parentNode);
						this.childNode = this._itemNodeMap[this.store.getIdentity(childObject)];
						this.nodeHighlighted = false;
						setTimeout("publishDelayEvent()", 1000);
					}
					return childObject;
					
				}
			}catch(e){
				console.debug(e);
				this.UIContext.log.logError(e);
			}
		},
		highlightNode:function(){
			if ((!this.nodeHighlighted) && (this.childNode)){
				this._publish("execute", { item: this.childNode.item, node: this.childNode} );
				this.onClick(this.childNode.item, this.childNode);
				this.blurNode();
				this.focusNode(this.childNode);
				this.nodeHighlighted = true;
			}
		},
		deleteTreeNode:function(treeNode){
		// summary:
		//		Remove a node from the tree.
			this.store.deleteItem(treeNode);
		},		
		getItemChildren: function(parentItem, onComplete){
			// summary
			// 		User overridable function that return array of child items of given parent item,
			//		or if parentItem==null then return top items in tree
			var store = this.store;
			if(parentItem == null){
				// get top level nodes
				this.createProgress();
				var _self = this;
				store.fetch({ query: this.query, onComplete: function(items){
					if (_self.initQuery){
						onComplete(items);
						_self.initQuery = false;
						_self.destroyProgress();
					}
				}});
			}else{
				// get children of specified node
				var childItems = [];
				var self = this;
				function setChildrenArray(children){
					childItems= childItems.concat(children);
					// count how many items need to be loaded
					var _waitCount = 0;
					dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
					if(_waitCount == 0){
						// all items are already loaded.  proceed..
						onComplete(childItems);
					}else{
						// still waiting for some or all of the items to load
						function onItem(item){
							if(--_waitCount == 0){
								// all nodes have been loaded, send them to the tree
								onComplete(childItems);
							}
						}
						dojo.forEach(childItems, function(item){
							if(!store.isItemLoaded(item)){
								store.loadItem({item: item, onItem: onItem});
							}
						});
					}
				}
				
				//only support 1 child attribute
				store.getValues(parentItem, this.childrenAttr[0], setChildrenArray);				
			}
		}
	}
	
);	

dojo.declare(
   "org.eclipse.cosmos.provisional.dr.ps.components.widget.NewNodeMenu",
	// superclass	
	null,
	{
		constructor: function(params){
			dojo.mixin(this,params);
		},
		widgetClass:'cosmos:QueryMenu',
		cmdbfQuery:null,
		createContextMenu: function(menu, store, className, index){
			//check for specific node class
			this.populateMenu(menu, store, className, index);
		},
		populateMenu:function(menu, store, className, index){
			var queryEPR = this.UIContext.getService(store.item, "http://cmdbf.org/schema/1-0-0/query");
			if (queryEPR == null) return;
			var self = this;
			menu.addChild(new dijit.MenuItem({item:this,UIContext:this.UIContext, store:store, sourceObject: this.sourceObject,onClick:function(){
				var sourceObject = this.sourceObject; 
				var store = this.store;
		    	var queryObject = this.UIContext.createObject(self.query);
                  queryObject.queryEPR = queryEPR;
		    	queryObject.bindInput(store.item, function(item){
					sourceObject.addQueryTreeNode(item, store.item, true);
				});
			},
			label:this.label,
			iconClass: (this.icon == null ? "" : this.icon)
			}));
		}
	}
);

dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.MetaDataMenu",
			// superclass	
			null,
			{
				constructor: function(params){
					dojo.mixin(this,params);
				},
				widgetClass:'cosmos:QueryMenu',
				cmdbfQuery:null,
				serviceMetatDataURL:"",
				serviceMetaData: null,
				createContextMenu: function(menu, store, className, index){
					//check for specific node class
					this.populateMenu(menu, store, className, index);
				},
				populateMenu:function(menu, store, className, index){
					var queryEPR = this.UIContext.getService(store.item, "http://cmdbf.org/schema/1-0-0/query");
					if (queryEPR == null) return;
					var self = this;	
					if (this.serviceMetaData == "none")
						return;
					else if (this.serviceMetaData){
						menu.addChild(new dijit.MenuItem({item:this,UIContext:this.UIContext, store:store, sourceObject: this.sourceObject,onClick:function(){
							var sourceObject = self.sourceObject; 
							var store = this.store;
					    	var queryObject = this.UIContext.createObject(self.query);
					    	queryObject.capability = this.serviceMetaData;
					    	queryObject.bindInput(store.item, function(item){
								sourceObject.addQueryTreeNode(item, store.item, true);
							});
						},
						label:this.label,
						iconClass: (this.icon == null ? "" : this.icon)
						}), index);
						
					}
					else{
						this.UIContext.submitQuery({item:store.item,queryObject: new org.eclipse.cosmos.provisional.dr.ps.components.utility.BasicQuery({queryHandler:this.serviceMetatDataURL+"&epr="+escape(queryEPR)}),
							onItem:function(response)
								{
									self.serviceMetatData = "none";
									if (response){
										if (!(response.capabilityUnknown)){
											self.serviceMetatData = response;
											menu.addChild(new dijit.MenuItem({item:this,UIContext:this.UIContext, store:store, sourceObject: this.sourceObject,onClick:function(){
												var sourceObject = self.sourceObject; 
												var store = this.store;
										    	var queryObject = self.UIContext.createObject(self.query);
										    	queryObject.capability = response;
										    	queryObject.bindInput(store.item, function(item){
													sourceObject.addQueryTreeNode(item, store.item, true);
												});
											},
											label:self.label,
											iconClass: (self.icon == null ? "" : self.icon)
											}), index);											
										}
									}
								}
						});
					}					
					
				}
			}
		);


dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu",
			// superclass
			null,
			{
				constructor: function(params){
					dojo.mixin(this,params);
				},
				widgetClass:'cosmos:QueryMenu',
				cmdbfQuery:null,
				createContextMenu:function(menu, store, className){
					var self = this;
					menu.addChild(new dijit.MenuItem({item:this,UIContext:this.UIContext, store:store, sourceObject: this.sourceObject,onClick:function(){
						var sourceObject = this.sourceObject; 
						var store = this.store;
				    	var queryObject = this.UIContext.createObject(self.query);
						this.UIContext.submitQuery({queryObject:queryObject, item:store.item, onItem:function(items){
							sourceObject.addTreeNode(items.items, store.item, true);
							}, queryProp:"query"});
					},
					label:this.label,
					iconClass: (this.icon == null ? "" : this.icon)
					}));
				}
			}
		);

dojo.declare(
		// class
		"org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryNavigator",

		// superclass	
		[org.eclipse.cosmos.provisional.dr.ps.components.widget.Navigator],
		
		// member variables/functions
		{
			queriesHandler:"json?service=org/eclipse/cosmos/internal/dr/drs/service/handler/common/QueriesOutputter",
			cmdbfQueryHandler:"json?service=org/eclipse/cosmos/internal/dr/drs/service/outputter/CMDBfQuery",
			unmarkProcessing: function(){
				//now we should add query nodes to the tree.
				this.addQueryNodes(null);
//				this.destroyProgress();
			},
		    getCMDBfResponse:function(args){
				var item = args.item;
		    	if (item.queryResponse){
		    		args.onItem(item.queryResponse);
		    		return item.queryResponse;
		    	}
				//check if this is a query node.
				if (item.query){
					//always submit a response?
					var queryEPR = this.UIContext.getService(item, "http://cmdbf.org/schema/1-0-0/query");
					if (queryEPR == null)
						queryEPR = item.epr[0];
					if (queryEPR != null){
						//reset uuid if not defined
						if (!(item.uuid))
							item.uuid = -1;
						this.UIContext.submitQuery({
										queryObject: new org.eclipse.cosmos.provisional.dr.ps.components.utility.BasicQuery(
												{
												 queryHandler:this.cmdbfQueryHandler, 
												 postData:"query="+escape(item.query)+"&epr="+escape(queryEPR)+"&queryClass="+item.nodeClass+"&uuid="+item.uuid,
												 handleAs:"text"
												}), 
									     onItem:function(response){
												item.queryResponse = response;
												if (args.onItem){
													args.onItem(response);
												}
										 }, 
										 item:item,
									     queryProp:"query"
									     									     
									    });
					}
				}					
		    },
		    addQueryTreeNode:function(/*dojo.data.Item[]*/newItem, /*dojo.data.Item*/parent, /*boolean*/expand){
		    	newItem.services = parent.services;		    	
		    	if  ((!newItem.isFolder) || (newItem.isFolder[0] != true)){
		    		newItem.getResponse = function(args){};
		    		dojo.connect(newItem, "getResponse", this, "getCMDBfResponse");
		    	}
		    	var _self = this;
		    	//if the item has a uuid then this means the query is already persisted
		    	if (!(newItem.uuid)){
					var postData="query="+escape(newItem.query)+"&title="+escape(newItem.title)+"&queryClass="+newItem.nodeClass;
					if ( (newItem.isFolder) && (newItem.isFolder[0] == true)){
						postData = postData + "&folder=true";
					}
					if  ((parent.isFolder) && (parent.isFolder[0] == true)){
						postData = postData+"&parentClass="+parent.uuid
					}
					else{
						postData = postData+"&parentClass="+parent.nodeClass
					}

					this.UIContext.submitQuery({
						queryObject: new org.eclipse.cosmos.provisional.dr.ps.components.utility.BasicQuery(
								{
								 queryHandler:this.saveQueryHandler, 
								 postData:postData,
								 handleAs:"text"
								}), 
							 item:newItem,
						     onItem:function(response){
									newItem.uuid = response;
									_self.addTreeNode(newItem, parent, expand);
							 }, 
					     queryProp:"query"
					    });		    		
		    	}
		    	else{
		    		this.addTreeNode(newItem, parent, expand);
		    	}
		    },
		    refreshQuery: function (/*Object*/ item, node, callback){
		    	item.queryResponse = null;
		    	var _self = this;
		    	//force refresh of graph response
		    	if ((item) && (item.getResponse)){
		    		dojo.addClass(node.expandoNode, "dijitTreeExpandoLoading");
		    		item.getResponse[0]({item:item,onItem:function(response){
						dojo.removeClass(node.expandoNode, "dijitTreeExpandoLoading");
		    			item.queryResponse  = response;
		    			if (callback)
		    				callback(response);
		    		}
		    		});
		    	}
		    	
		    	
		    },
		    treeHandler: function(/*Object*/message){
				//summary: This method is called when the user selects a node
				//description: The message parameter contains the node that was selected.  The message parameter is cloned and published to 
				//  topics specified by the the publish memeber variable of this class.
		    	var _self = this;
		    	var _arg = arguments;
		    	if ((message.node.item) && (!message.node.item.queryResponse) && (message.node.item.getResponse) && ((!message.node.item.isFolder) || (message.node.item.isFolder[0] != true))){
		    		dojo.addClass(message.node.expandoNode, "dijitTreeExpandoLoading");
		    		
		    		message.node.item.getResponse[0]({item:message.node.item,onItem:function(response){
						dojo.removeClass(message.node.expandoNode, "dijitTreeExpandoLoading");
		    			_self.inherited(_arg);		    			
		    		}
		    		});
		    	}
		    	else{
		    		this.inherited(arguments);
		    	}
		    },		    
			addQueryNodes: function(parentItem){
				var _self = this;
				this.getItemChildren(parentItem, function(items){
					var classList = {}; 
						for (i=0;i < items.length;i++){
					    	if  ((items[i].isFolder) && (items[i].isFolder[0] == true)){
								classList[items[i].uuid] = items[i].uuid;
					    	}
					    	else if (!(classList[items[i].nodeClass])){
									classList[items[i].nodeClass] = items[i].nodeClass;
							}
						}
						var classStrings = "";
						for(nodeClassStr in classList) {  
							classStrings = classStrings+nodeClassStr+",";
						}
					var addQueries = function(response){
						for (i=0;i < items.length;i++){
							if ((response[items[i].nodeClass])||((items[i].uuid) && response[items[i].uuid[0]])){
								var nodeObjs = response[items[i].nodeClass];
								if (response[items[i].uuid]){									
									if (nodeObjs){
										for (j=0;j < response[items[i].uuid[0]].length;j++){
											nodeObjs.push(response[items[i].uuid[0]][j]);
										}
									}
									else{
										nodeObjs = response[items[i].uuid[0]];
									}
								}
								for (j=0;j < nodeObjs.length;j++){
									var nodeObj = new Object();
							 	    dojo.mixin(nodeObj,nodeObjs[j].meta);
							 	    nodeObj.readonly = nodeObjs[j].readonly;
									if ( nodeObjs[j].query)
										nodeObj.query = nodeObjs[j].query;
										//make node unique
										nodeObj.object = dojo.dnd.getUniqueId();
	
										//determine if we need to inherit attributes from parent
										var parent = items[i];
										for(attribute in nodeObj) {  
											if (nodeObj[attribute] == "__inherit__"){
												if (parent[attribute])
													nodeObj[attribute] = parent[attribute];
											}
											//treat query and title as special attributes that we have to process
										}
										for(attribute in nodeObj) { 
											if ((attribute=="title") || (attribute=="query")){
												nodeObj[attribute] = dojo.string.substitute(nodeObj[attribute], nodeObj); 							
											}
										}
									
									_self.addQueryTreeNode(nodeObj, items[i], false);
									var childNode = _self._itemNodeMap[_self.store.getIdentity(items[i])];
									childNode.childDoneLoading = function(){
										if (this.item.process) return;
										this.item.process = true;
										_self.addQueryNodes(this.item);
									}
								}
								dojo.connect(childNode, "expand", childNode, "childDoneLoading");
							}
						}
					}
					_self.UIContext.submitRequest({url:_self.queriesHandler+"&nodeClass="+classStrings, postData:"", onItem: addQueries});
				});					
			}
			
			
		}
);
dojo.declare(
   "org.eclipse.cosmos.provisional.dr.ps.components.widget.RemoveMenu",
	// superclass	
	org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu,
	{
		widgetClass:'cosmos:RemoveMenu',
		createContextMenu: function(menu, store, className){
			this.inherited(arguments);
		},
		populateMenu:function(menu, store, className){
			menu.addChild(new dijit.MenuItem({onClick:function(){
				store.tree.deleteTreeNode(store.item);
			},
			label:this.label
			}));
		}
	}
); 
dojo.declare
(
	 "org.eclipse.cosmos.provisional.dr.ps.components.widget.ViewMenu",
        // superclass
	 null,
  {
    constructor: function(params){
			dojo.mixin(this,params);
	},
    widgetClass:'cosmos:ViewMenu',
    createContextMenu: function(menu, store, className)
    {
	  var metaEPR = this.UIContext.getService(store.item, "http://cmdbf.org/schema/1-0-0/query");
	  if (metaEPR == null) return;
	  var _self = this;
      menu.addChild(new dijit.MenuItem(
      { onClick:
        function()
        {
          if (typeof(_self.publish) != 'undefined')
          {
             //clone item since we don't want to modify the original item
             var contextMap = store.item;
             contextMap.contentNode = _self.url + "&mdr="+escape(metaEPR);
             for (y=0;y < _self.publish.length;y++)
               	 dojo.publish(_self.publish[y], [{contextMap:contextMap}]);
          }
        },
		label:this.label,
		iconClass: (this.icon == null ? "" : this.icon)
      }
      ));
    }
  }
);

dojo.declare
(
	 "org.eclipse.cosmos.provisional.dr.ps.components.widget.RefreshQueryMenu",
        // superclass
	 null,
  {
    constructor: function(params){
			dojo.mixin(this,params);
	},
    widgetClass:'cosmos:ViewMenu',
    createContextMenu: function(menu, store, className)
    {
	  var _self = this;
		menu.addChild(new dijit.MenuItem({onClick:function(){
			store.tree.refreshQuery(store.item, store);
			store.tree.publishItemMessage(store.item, null);
		},
		label:_self.label,
		iconClass: (_self.icon == null ? "" : _self.icon)
		}));
    }
  }
);

dojo.declare
(
	 "org.eclipse.cosmos.provisional.dr.ps.components.widget.ResponseHistoryMenu",
        // superclass
	 null,
  {
    constructor: function(params){
			dojo.mixin(this,params);
	},
    widgetClass:'cosmos:ViewMenu',
	_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),
    createContextMenu: function(menu, store, className)
    {
	  var _self = this;
 	  var addQueries = function(response){
		if (response){
			if (dojo.isArray(response)){
	 			var subMenu = new dijit.Menu({label:_self._message.RESPONSEHISTORY});
	 	 	    var popupItem =  new dijit.PopupMenuItem({ label: _self._message.RESPONSEHISTORY , popup:subMenu });	 	 	        
	 	 		menu.addChild(popupItem);
				
				for (i=0;i < response.length;i++){
		 		  var menuItem = new dijit.PopupMenuItem({historyId:response[i].instanceId,onClick:function(){
		 				store.tree.publishItemMessage(store.item, {historyId: this.historyId});
		 			},
		 			label:response[i].title
		 			});
	 	 	  	    subMenu.addChild(menuItem);
				}
			}
 		  
		}
 	  }	  
      _self.UIContext.submitRequest({url:_self.responseHistoryHandler+"&uuid="+store.item.uuid, postData:"", onItem: addQueries});	  	  
  }
  }
);


dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.RenameQueryDialogMenu",
			// superclass
			org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu,
			{
				builder: null,
				name:"",		
				_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),				
				createContextMenu:function(menu, store, className){
			   		//if query is readonly then user can not rename query
			   		if (store.item.readonly){
			   			if (store.item.readonly[0] == true) return;
					}
			   		var _self = this;
					menu.addChild(new dijit.MenuItem({onClick:function(){
			   			if (dijit.byId("renameQueryDialog") != null)
			   				dijit.byId("renameQueryDialog").destroy();
						_self.builder = new org.eclipse.cosmos.provisional.dr.ps.components.widget.RenameQueryDialog({
								name:store.item.title,
								callback:function(args){
									store.setLabelNode(args.name);
									store.item.title = args.name;
									//make call to save to persisted query on server side
									var isFolder = false;
									if (((store.item.isFolder) && (store.item.isFolder[0] == true)))
										isFolder = true;
									var postData="func=rename&folder="+isFolder+"&title="+escape(args.name)+"&uuid="+store.item.uuid+"&queryClass="+store.item.nodeClass;
									if (((store.getParent()) && (store.getParent().item.isFolder) && (store.getParent().item.isFolder[0] == true))){
										postData = postData+"&parentClass="+store.getParent().item.uuid
									}
									else{
										postData = postData+"&parentClass="+store.getParent().item.nodeClass
									}
									
									_self.UIContext.submitQuery({
										queryObject: new org.eclipse.cosmos.provisional.dr.ps.components.utility.BasicQuery(
												{
												item:store.item,
												 queryHandler:_self.renameQueryHandler, 
												 postData:postData,
												 handleAs:"text"
												}), 
									     queryProp:"query"
									    });		    		
								}});
						_self.builder.show();
					},
					label:this._message.RENAMEQUERY,
					iconClass:(this.icon == null ? "" : this.icon)
					}));
				}
			}
		); 

dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.DeleteQueryMenu",
			// superclass
			org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu,
			{
				builder: null,
				name:"",		
				_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),				
				createContextMenu:function(menu, store, className){
			   		//if query is readonly then user can not delete query
			   		if (store.item.readonly){
			   			if (store.item.readonly[0] == true) return;
					}
			   		var _self = this;
					menu.addChild(new dijit.MenuItem({onClick:function(){
						var isFolder = false;
						if (((store.item.isFolder) && (store.item.isFolder[0] == true)))
							isFolder = true;
						var postData="func=delete&folder="+isFolder+"&title=deleting&uuid="+store.item.uuid+"&queryClass="+store.item.nodeClass;
						if (((store.getParent()) && (store.getParent().item.isFolder) && (store.getParent().item.isFolder[0] == true))){
							postData = postData+"&parentClass="+store.getParent().item.uuid
						}
						else{
							postData = postData+"&parentClass="+store.getParent().item.nodeClass
						}
						_self.UIContext.submitQuery(
								{
									onItem:function(response){},										
									queryObject: new org.eclipse.cosmos.provisional.dr.ps.components.utility.BasicQuery(
									{
										item:store.item,
										queryHandler:_self.deleteQueryHandler, 
										postData:postData,
										 handleAs:"text"
									}), 
									queryProp:"query"
							    });	
						store.tree.deleteTreeNode(store.item);
					},
					label:this._message.DELETEQUERY,
					iconClass:(this.icon == null ? "" : this.icon)
					}));
				}
			}
		); 

dojo.declare(
		"org.eclipse.cosmos.provisional.dr.ps.components.widget.RenameQueryDialog",
		[org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryDialog], 
		{
			templatePath:dojo.moduleUrl("org.eclipse.cosmos.provisional.dr.ps.components.widget", "html/RenameQuery.html"),
			_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),			
			name:"",
			dialogIcon:"",
			widgetId: "renameQueryDialog",
			submitQuery: function(){
				if (!(document.getElementById(this.id+"_name"))) return;
				var name = document.getElementById(this.id+"_name").value;
			    var trimname =  name.replace(/^\s*/, "").replace(/\s*$/, "");
				if (trimname != ""){
					this.callback({name:trimname});
			   		
				}
				
				this.destroy();
			},
			onKeyEvt: function(/*Event*/ evt){
				// summary: keep keyboard focus in dialog; close dialog on escape key
				if(evt.keyCode == dojo.keys.ENTER){
					this.submitQuery();
					this.destroy();
				}
			},		
			create: function(params, srcNodeRef) {
				this.labelQuery= this._message.NAME;
				this.title= this._message.RENAMEQUERY;
				this.inherited(arguments);
			},
			postMixInProperties: function()
			{
				// set the dialog in the dialog box dependent on whether it is register or deregister
				// this should go in a jprop file, but as yet its unknown where (Martin).
				this.dialogIcon = "<span class='dialogRenameQueryWinIcon'></span>";

				//call superclass
				org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryDialog.superclass.postMixInProperties.apply(this, arguments);
			},
			postCreate: function(){
				//need to programmically create the combobox due to timing issues with the store
				//call superclass
				this.inherited("postCreate", arguments);
				dojo.connect(this.dialogBox, "_onKey", this, "onKeyEvt");			
			}
		
		
			
		}
	);

dojo.declare(
		"org.eclipse.cosmos.provisional.dr.ps.components.widget.NewQueryFolderDialog",
		[org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryDialog], 
		{
			widgetId: "newFolderDialog",			
			templatePath:dojo.moduleUrl("org.eclipse.cosmos.provisional.dr.ps.components.widget", "html/NewQueryFolder.html"),
			submitQuery: function(){
				if (!(document.getElementById(this.id+"_newFolder"))) return;
				var newFolder = document.getElementById(this.id+"_newFolder").value;
			    var newFolder =  newFolder.replace(/^\s*/, "").replace(/\s*$/, "");
				if (newFolder != ""){
					this.callback({title:newFolder,nodeClass:"newFolder",object:this.id, isFolder:[true],readonly:[false]});
				}
				
				this.destroy();
			},
			show: function(){
				//summary: displays the dialog box on the screen
				this.inherited(arguments);
			}
		}
	);

dojo.declare(
		"org.eclipse.cosmos.provisional.dr.ps.components.widget.MDRPropertiesDialog",
		[org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryDialog], 
		{
			widgetId: "MDRPropertiesDialog",			
			templatePath:dojo.moduleUrl("org.eclipse.cosmos.provisional.dr.ps.components.widget", "html/MDRPropertiesDialog.html"),
			username:"",
			password:"",
			dialogIcon:"",
			soapversion: "12",
			create: function(params, srcNodeRef) {
				this.usernameLbl=this._message.USERNAME;
				this.passwordLbl=this._message.PASSWORD;
				this.soapversionLbl=this._message.SOAPVERSION;
				if (params.soapversion == "12"){
					this.option2Selected="selected";
					this.option1Selected="";
				}
				else{
					this.option1Selected="selected";
					this.option2Selected="";
				}
				this.inherited(arguments);
			},		
			postMixInProperties: function(){

				this.dialogIcon="<span class='dialogPropertiesTableWinIcon'></span>"; 
				//call superclass
				org.eclipse.cosmos.provisional.dr.ps.components.widget.MDRPropertiesDialog.superclass.postMixInProperties.apply(this, arguments);
			},

			submitQuery: function(){
				if (!(document.getElementById(this.id+"_username"))) return;
				var username = document.getElementById(this.id+"_username").value;
			    username =  username.replace(/^\s*/, "").replace(/\s*$/, "");
				if (!(document.getElementById(this.id+"_password"))) return;
				var password = document.getElementById(this.id+"_password").value;
			    password =  password.replace(/^\s*/, "").replace(/\s*$/, "");
				if (!(document.getElementById(this.id+"_soapversion"))) return;
				var soapversion = document.getElementById(this.id+"_soapversion").value;
			    soapversion =  soapversion.replace(/^\s*/, "").replace(/\s*$/, "");
			    var returnobj = {};
				if (username != ""){
					returnobj.username=username;
					returnobj.password=password;
				}
				if (soapversion != ""){
					returnobj.soapversion = soapversion;
				}
				this.callback(returnobj);
				this.destroy();
			},
			show: function(){
				//summary: displays the dialog box on the screen
				this.inherited(arguments);
			}
		}
	);


dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.NewQueryFolderMenu",
			// superclass
			org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu,
			{
				builder: null,
				name:"",		
				_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),				
				createContextMenu:function(menu, store, className){
			   		//if query is readonly then user can not rename query

			   		var _self = this;
					menu.addChild(new dijit.MenuItem({onClick:function(){
			   			if (dijit.byId("newFolderDialog") != null)
			   				dijit.byId("newFolderDialog").destroy();
						_self.builder = new org.eclipse.cosmos.provisional.dr.ps.components.widget.NewQueryFolderDialog({
								name:store.item.title,
								title:_self._message.NEWFOLDERTITLE,								
								callback:function(item){
									//need to set epr
									item.services = store.item.services;
									_self.sourceObject.addQueryTreeNode(item, store.item, true);
								}});
						_self.builder.show();
					},
					label:this._message.NEWFOLDERQUERY,
					iconClass: (this.icon == null ? "" : this.icon)
					}));
				}
			}
		); 

dojo.declare(
		   "org.eclipse.cosmos.provisional.dr.ps.components.widget.RegisterPropertiesHandlerMenu",
			// superclass
			org.eclipse.cosmos.provisional.dr.ps.components.widget.QueryMenu,
			{
				builder: null,
				name:"",	
				propertiesHandler:"org.eclipse.cosmos.provisional.dr.ps.components.utility.SimplePropertiesObject",
				_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),				
				createContextMenu:function(menu, store, className){
			   		//if query is readonly then user can not rename query

			   		var _self = this;
					menu.addChild(new dijit.MenuItem({onClick:function(){
			   			if (dijit.byId("MDRPropertiesDialog") != null)
			   				dijit.byId("MDRPropertiesDialog").destroy();
			   				var username ="";
			   				var password = "";
			   				var soapversion = "";
			   				if (store.item.propertiesHandler){
			   					username = store.item.propertiesHandler.username;
			   					password = store.item.propertiesHandler.password;
			   					soapversion = store.item.propertiesHandler.soapversion;
			   				}
						_self.builder = new org.eclipse.cosmos.provisional.dr.ps.components.widget.MDRPropertiesDialog({
								name:_self._message.PROPERTIES,
								title:_self._message.PROPERTIES,		
								username:username,
								password:password,
								soapversion:soapversion,
								callback:function(properties){
									//need to set epr
									if (!store.item.propertiesHandler)
										store.item.propertiesHandler = eval("new "+_self.propertiesHandler+"(properties)");
									else
										store.item.propertiesHandler.update(properties);	 
								}});
						_self.builder.show();
					},
					label:this._message.PROPERTIES+"...",
					iconClass: (this.icon == null ? "" : this.icon)
					}));
				}
			}
		); 


// This should be more extensible in the future
dojo.declare
(
	"org.eclipse.cosmos.provisional.dr.ps.components.widget.OpenMultipleViews",
        
	// superclass
	null,
	{
		NAVIGATOR_VIEW_NAME: "nav",									// The navigator view name
		HIERARCHICAL_VIEW_NAME: "queryCMDBf",						// Should match a folder name under views/NAVIGATOR_VIEW_NAME
		TABULAR_VIEW_NAME: "tabularResponseView",					// Should match a folder name under views/NAVIGATOR_VIEW_NAME
		DETAIL_ATTACH_POINT: "detail",								// The detail attach point
		
		_message: dojo.i18n.getLocalization("nls.org.eclipse.cosmos.provisional.dr.ps.components", "widget"),	
		
		
		constructor: function(params)
		{
			dojo.mixin(this,params);
		},
		
		widgetClass:'cosmos:ViewMenu',
		
		createContextMenu: function(menu, store, className)
		{
 			var subMenu = new dijit.Menu();
 	 	    var popupItem =  new dijit.PopupMenuItem({ label: this._message.CONTEXT_OPEN_WITH, popup:subMenu });	 	 	        
 	 		menu.addChild(popupItem);

 	 		subMenu.addChild(this.createMenuItem(store, 
 	 				this._message.CONTEXT_MENU_HIERARCHICAL, 
 	 				this.HIERARCHICAL_VIEW_NAME,
 	 				"hierarchicalIcon"));
			
 	 		subMenu.addChild(this.createMenuItem(store, 
					this._message.CONTEXT_MENU_TABULAR, 
					this.TABULAR_VIEW_NAME, 
					"tabularIcon"));
		},
		
		createMenuItem: function (store, label, viewName, iconClass)
		{
			var _self = this;
			return new dijit.PopupMenuItem(
			{ 
				onClick:function()
				{
					//lets clone the information we're going to send to another widget since we don't want the other
			 	    //widget modifying our content
					var cloneMap = new Object();
					var item = store.item;					
					
					var onComplete = function()
					{
						dojo.mixin(cloneMap,item);
				 	    
						//let tag the data we're going to send so that the consumer of this data knows where the data came from
						item.viewClass = viewName;
				 	    cloneMap.nodeClass = _self.NAVIGATOR_VIEW_NAME + " " + viewName;				 	   
						dojo.publish(_self.DETAIL_ATTACH_POINT, [{contextMap:cloneMap}]);	
					};
					
					if (typeof(item.queryResponse) == 'undefined' || item.queryResponse == null)
					{
						store.onItem = onComplete;
						store.tree.getCMDBfResponse(store);
					}			 	   				
					else
					{
						onComplete();
					}
	 			},
	 			label:label,
	 			iconClass: (iconClass == null ? "" : iconClass)
	 		});
		}
	}
);



dojo.declare
(
	"org.eclipse.cosmos.provisional.dr.ps.components.widget.MenuSeparator",
        
	// superclass
	null,
	{		
		constructor: function(params)
		{
			dojo.mixin(this,params);
		},
		
		widgetClass:'cosmos:ViewMenu',
		
		createContextMenu: function(menu, store, className)
		{ 			      
 	 		menu.addChild(new dijit.MenuSeparator());
		}
	}
);