/*
	Copyright (c) 2006-2007, ePages GmbH
	All Rights Reserved.

	epages.cartridges.de_epages.presentation.widget.Objectcontroller

*/
dojo.provide("epages.cartridges.de_epages.presentation.widget.Objecttree");
dojo.require("dijit.Tree");
dojo.require("epages.event");

dojo.declare(
	"epages.cartridges.de_epages.presentation.widget.Objecttree",
	[dijit.Tree],
	{
		/**
		 * public properties
		 */
		selectedNodeId     : undefined,
		persist            : false,
		/**
		 * private properties
		 */
		_translation       : new epages.io.Translation(dojo.moduleUrl('epages.cartridges.de_epages.presentation.widget', 'templates/translation'), 'auto'), // epages.io.Translation - translation object

		postCreate  : function() {
			this.inherited("postCreate", arguments);
			dojo.subscribe(this.model.store.id+'/changePosition',this,'_onStoreChangePosition');
			dojo.subscribe(this.model.store.id+'/changeParent',this,'_onStoreChangeParent');
			dojo.subscribe(this.model.store.id+'/changeVisibility',this,'_onStoreChangeVisibility');
			dojo.subscribe(this.model.store.id+'/reloadStore',this,'_reloadTree');
			var me = this;
			//set Children state when node expands
			dojo.subscribe(this.id+'/nodeexpand',function(node){
				me.setChildrenState(node);
				});
			// add item for root object
			 this.item = this.model.store.fetchItemByIdentity(this.model.query.id);
			 dojo.mixin(this.rootNode.item,this.item);
			// set Selected node on load
			if(this.selectedNodeId){
				this.focusNodeById(this.selectedNodeId);
			}

			//set Icons for Children of Tree and connect setChildren method to prototype of TreeNodes
			this.setChildrenState(this.rootNode);
			// set Icon of root node

			this.setState(this.rootNode,this.item.IsVisibleContentView);
		},

		focusNodeById: function(/* objectid */id) {
			// summary: expands & selects node in tree
				var currentItem = this.model.store.fetchItemByIdentity(id);
				var path = [id];
				while (currentItem.objectId != this.model.query.id) {
					currentItem = this.model.store.fetchItemByIdentity(currentItem.parentId);
					if(currentItem == undefined){
						return;
					}
					path.unshift(currentItem.objectId);
				}
				this.item.parentId = undefined;
				for( var i=0,iLength=path.length ; i<iLength ; i++ ) {
					var objectId = path[i];
					var node = this._getNodeByObjectId(objectId);
					if(node.rootNode){
						this._expandNode(node.rootNode);
					}
					else{
						this._expandNode(node);
					}
					if (i == path.length - 1) {
						if(node.rootNode){
							node = node.rootNode;
							this.item = this.model.store.fetchItemByIdentity(this.item.objectId);
							node.item = this.item;
						}
						window.setTimeout(dojo.hitch(this,this._onNodeFocus,node),20);
						epages.event.fire(node.labelNode, 'focus');
						// timeout is needed, without timeout after reload the tree does not select the current element correct
						//caused problems in the ToolNewPage EPG-27243
						window.setTimeout(function(){
							epages.event.fire(node.labelNode, 'click');
						},1);

						dojo.publish(this.id+'/select',[node]);
						if(epages && epages.vars){
							epages.vars.currentSelectedObjectID = node.item.objectId;
						}
					}
				}
			},

		focusNode: function(node) {
			this._onNodeFocus(node);
		},
		_onNodeFocus: function(/*dijit._Widget*/ node){
			// summary:
			//		Called when a TreeNode gets focus, either by user clicking
			//		it, or programatically by arrow key handling code.
			// description:
			//		It marks that the current node is the selected one, and the previously
			//		selected node no longer is.

			if(node){
				if(node != this.lastFocused && this.lastFocused && !this.lastFocused._destroyed){
					// mark that the previously selected node is no longer the selected one
					this.blurNode();
					this.lastFocused.setSelected(false);
				}

				// mark that the new node is the currently selected one
				dojo.addClass(node.labelNode,"Selected");
				node.setSelected(true);
				this.lastFocused = node;
			}
		},

		blurNode: function() {
			var node = this.lastFocused;
			if(!node){
				return;
			}
			var labelNode = node.labelNode;
			dojo.removeClass(labelNode, "Selected");
			labelNode.setAttribute("tabIndex", "-1");
		},

		onClick: function(item, node){
			if(item && item.children !== undefined){
				this._expandNode(node);

				this.setChildrenState(node);
			}
			dojo.publish(this.id+'/select',[node]);
			if(epages && epages.vars){
				epages.vars.currentSelectedObjectID = node.item.objectId;
			}
			//if item with to many children error was clicked restore expand node
			var item = this.model.store.fetchItemByIdentity(node.item.objectId);
			if(item.error && item.error == 'ERROR_TOO_MANY_CHILDREN'){
				node.state = "UNCHECKED";
				node.isExpandable = true;
				node._setExpando(false);
			}

			// use jquery to release event in top frame (force blur for active CKEditors)
			top.jq('body').trigger("click");
		},

		selectNodeByObjectId : function(/* string */ objectId) {
		// summary:  select a tree node by object id
			var node = this._getNodeByObjectId(objectId);
			this.onClick(node.item, node.rootNode ? node.rootNode : node);
		},

		currentItem: function(){
			return this.lastFocused.item;
		},

		currentObjectID: function(){
			return this.lastFocused.item.objectId;
		},

		deleteCurrent: function() {
			var node = this.lastFocused;
			//treenode cant't be delete
			if (node === undefined || node.rootNode || node.item.ClassAlias == "StartPage"  || node.item.isProduct == true){
				return;
			}
			if(this.model.store.deleteItem(node.item)){
				node.domNode.style.display = "none";
			}
			var parentNode = node.getParent();
			if(parentNode){
				this._onNodeFocus(parentNode);
				dojo.publish(this.id+'/select',[parentNode]);
				if(epages && epages.vars){
					epages.vars.currentSelectedObjectID = parentNode.item.objectId;
				}
				var children = parentNode.getChildren();
				var visible = false;
				for( var i=0,iLength=children.length ; i<iLength ; i++ ){
					if(children[i].domNode.style.display != "none"){
						visible = true;
					}
				}
				if(visible != true){
					parentNode.isExpandable = false;
					parentNode.isExpanded = false;
					parentNode._setExpando(false);
				}
			}
		},

		moveUpCurrent:   function () {
			var node = this.lastFocused;
			//can not move (tree node) or products
			if (node === undefined || node.rootNode || node.item.isProduct){
				return;
			}
			if(this.model.store.moveItem(-1,node.item)){
				var parentWidget = node.getParent();
				var TreeNodes = parentWidget.getChildren();
				var index = $A(TreeNodes).find(node);
				$A(TreeNodes).insertAt(index-1,node);
				$A(TreeNodes).remove(index+1);
				$A(TreeNodes).each(function(el) {
					parentWidget.addChild(el);
				});
				this._onNodeFocus(node);
			}
		},

		moveDownCurrent: function () {
			var node = this.lastFocused;
			//can not move (tree node) or products
			if (node === undefined || node.rootNode || node.item.isProduct){
				return;
			}
			if(this.model.store.moveItem( 1,node.item)){
				var parentWidget = node.getParent();
				var TreeNodes = parentWidget.getChildren();
				var index = $A(TreeNodes).find(node);
				$A(TreeNodes).insertAt(index+2,node);
				$A(TreeNodes).remove(index);
				$A(TreeNodes).each(function(el) {
					parentWidget.addChild(el);
				});
				this._onNodeFocus(node);
			}
		},

		_onStoreChangePosition: function(opt){
			var node = this._getNodeByObjectId(opt.item.objectId);
			var newPosition = opt.item.position;
			var oldPosition = opt.oldPosition;
			var parentWidget = node.getParent();
			var treeNodes = parentWidget.getChildren();
			var treeNodesArray = $A(treeNodes);
			//find old Position in ChildrenArray
			var index = treeNodesArray.find(node);
			if(oldPosition == newPosition){
				this._reloadTree();
				return;
			}
			if(oldPosition > newPosition){
				//move up
				if(index == 0){
					console.warn('first in Array can not move up');
				}
				else{
					//insert one element before and remove old element
					treeNodesArray.insertAt(index-1,node);
					treeNodesArray.remove(index+1);
				}
			}
			if(oldPosition < newPosition){
				//move down
				//insert one element after and remove old element
				treeNodesArray.insertAt(index+2,node);
				treeNodesArray.remove(index);
			}
			treeNodesArray.each(function(el) {
					parentWidget.addChild(el);
				});
		},

		_reloadNode: function(node){
			if(node.isExpanded == true){
				this._collapseNode(node);
			}
			node.state = "UNCHECKED";
			if(node.item.children && node.item.children.length > 0){
				node.isExpandable = true;
				node._setExpando(false);
				this._expandNode(node);
			}
			else{
				node.isExpandable = false;
				node._setExpando(false);
			}
			this.setState(node,node.item.IsVisibleContentView);
		},

		_reloadTree: function(noFocus){
			var lastId = (this.lastFocused) ? this.lastFocused.item.objectId : undefined;
			this._itemNodesMap = {};
			this.rootNode.item = this.model.store.fetchItemByIdentity(this.rootNode.item.objectId, true);
			this._reloadNode(this.rootNode);
			if(lastId && !noFocus){
				this.focusNodeById(lastId);
			}
		},

		_getNodeByObjectId: function(objectId, parentNode) {
			if (parentNode == undefined){
				parentNode = this.rootNode;
			}
			if(objectId == this.item.objectId){
				return this;
			}
			var nodesWithChildren = [];
			var children = parentNode.getChildren();
			for( var i=0,iLength=children.length ; i<iLength ; i++ ) {
				var node = children[i];
				if (node.item.objectId == objectId){
					return node;
				}
				if (node.getChildren() && node.getChildren().length > 0){
					nodesWithChildren.push(node);
				}
			}
			for( var i=0,iLength=nodesWithChildren.length ; i<iLength ; i++ ) {
				var node = this._getNodeByObjectId(objectId, nodesWithChildren[i]);
				if (node != null){
					return node;
				}
			}
			return null;
		},

		_onStoreChangeParent: function(opt){
			var node = this._getNodeByObjectId(opt.item.objectId);
			if(!node){
				//console.debug('cant find node');
				 return;
				}
			if(opt['delete']){
				node.domNode.style.display = 'none';
				var parentNode = node.getParent();
				if(parentNode){
					this._onNodeFocus(parentNode);
					dojo.publish(this.id+'/select',[parentNode]);
				}
				return;
			}
			//if Old Parent and New Parent equal than the it was an undo delete
			if(opt.oldParent == opt.item.parentId){
				node.domNode.style.display = '';
				return;
			}
			var oldParentNode = this._getNodeByObjectId(opt.oldParent);
			var newParentNode = this._getNodeByObjectId(opt.item.parentId);
			if(oldParentNode.rootNode){
				this._indentNode(node,newParentNode,oldParentNode.rootNode);
			}
			else if(newParentNode.rootNode){
				this._outdentNode(node,newParentNode.rootNode,oldParentNode);
			}
			else{
				if($A(newParentNode.item.children).exists(oldParentNode.item.objectId)){
					this._outdentNode(node,newParentNode,oldParentNode);
				}
				if($A(oldParentNode.item.children).exists(newParentNode.item.objectId)){
					this._indentNode(node,newParentNode,oldParentNode);
				}
			}
		},

		_indentNode: function(node,newParentNode,oldParentNode){
			newParentNode.item = this.model.store.fetchItemByIdentity(newParentNode.item.objectId);
			oldParentNode.item = this.model.store.fetchItemByIdentity(oldParentNode.item.objectId);
			this._reloadNode(newParentNode);
			this._reloadNode(oldParentNode);
			var objectId = node.item.objectId;
			var newNode = this._getNodeByObjectId(objectId);
			this._onNodeFocus(newNode);
		},

		indentCurrent: function () {
			var node = this.lastFocused;
			//can not indent (tree node) or products
			if (node === undefined || node.rootNode || node.item.isProduct){
				return;
			}
			var oldParentNode = this._getNodeByObjectId(node.item.parentId);
			if(oldParentNode.rootNode){
				oldParentNode = oldParentNode.rootNode;
			}
			var newParentObjectId = this.model.store.indentItem(node.item);
			if(newParentObjectId){
				var newParentNode = this._getNodeByObjectId(newParentObjectId);
				// Flag to decide if a node is indented or outdented
				this.model.store.indentNode = true;
				this._indentNode(node,newParentNode,oldParentNode);
			}
			else{
				console.warn('can not ident');
			}
		},

		_outdentNode: function(node,newParentNode,oldParentNode){
			this._reloadNode(newParentNode);
			this._reloadNode(oldParentNode);
			var objectId = node.item.objectId;
			var newNode = this._getNodeByObjectId(objectId);
			this._onNodeFocus(newNode);
		},

		outdentCurrent: function () {
			var node = this.lastFocused;
			// can not outdent tree node (start page)
			if (node === undefined || node.rootNode || node.item.isProduct){
				return;
			}
			// can not outdent first level
			var oldParentNode = this._getNodeByObjectId(node.item.parentId);
			if (oldParentNode == undefined || oldParentNode.rootNode){
				return;
			}
			// find position of parent to insert node behind
			var newParentObjectId = this.model.store.outdentItem(node.item);
			if(newParentObjectId){
				var newParentNode = this._getNodeByObjectId(newParentObjectId);
				// Flag to decide if a node is indented or outdented
				this.model.store.indentNode = true;
				if(!newParentNode || newParentNode.rootNode){
					newParentNode = this.rootNode;
				}
				this._outdentNode(node,newParentNode,oldParentNode);
			}
	},

		createObject: function (/* form element */ classNode, /* form element */ nameNode, /* string? */ enterNameMessage, /* string? */ insertParentObjectId,isVisible) {
		// summary:
		//		create a new object
		// classNode:
		//		form element with class node id
		// nameNode:
		// 		form element with object name
		// enterNameMessage:
		//		possibility to pass e debug message if nameNode value is empty
		// insertParentObjectId:
		// 	  specify a different parent object

			var node = this.lastFocused;
			if (node === undefined){
				return;
			}
			var objectId = undefined;
			if(node.item){
				objectId = node.item.objectId;
			}	else{
				if(node.rootNode){
					objectId = this.model.store.objectId;
				}
			}
			if(insertParentObjectId && this.model.store.fetchItemByIdentity(insertParentObjectId)) {	// override current parent object
				objectId = insertParentObjectId;
			}
			if(!objectId){
				return;
			}
			var name = $E(nameNode).get();
			var classId = $E(classNode).get();
			if (name == '') {
				if (enterNameMessage == ''){
					enterNameMessage = 'Enter a name !';
				}
				console.warn(enterNameMessage);
				return;
			}
			newItem = this.model.store.createObject(objectId, classId, name,isVisible);
			if(newItem){
				node.item = this.model.store.fetchItemByIdentity(node.item.objectId);
				if(!node.isExpandable){
					node.makeExpandable();
				}
				this._reloadTree(true);
				//check if all children of parent are visible (not marked as deleted)
				var children = node.getChildren();
				for( var i=0,iLength=children.length ; i<iLength ; i++ ){
					//correct is deleted after reload
					if($('parentInput_'+children[i].item.objectId) && $('parentInput_'+children[i].item.objectId).value == 'Delete'){
						children[i].item.isDeleted = true;
					}
					if(children[i].item.isDeleted == true){
						children[i].domNode.style.display = 'none';
					}
				}
				var newNode = this._getNodeByObjectId(newItem.objectId);
				this.focusNodeById(newItem.objectId);
			}
			else {
				console.warn('unable to created object in '+ this.declaredClass);
			}
		},

		getIconClass: function(/*dojo.data.Item*/ item){
				return item.persistentIconClass || '';
		},
		getLabelClass: function(/*dojo.data.Item*/ item){
			// summary: user overridable function to return CSS class name to display label
			// description: if no return value is set dojo adds a class "undefined" to every label in the tree
			// tags: extendable
			return '';
		},

		setChildrenState: function(node){
			var children = node.getChildren();
			for( var i=0,iLength=children.length ; i<iLength ; i++ ){
				this.setState(children[i],children[i].item.IsVisibleContentView);
			}
		},

		setState: function(node,IsVisibleContentView){
			IsVisibleContentView = parseInt(IsVisibleContentView);
			var item = node.item;
			if(node.rootNode){
				item =this.item;
				node = node.rootNode;
			}
			//remove class Icon of IconNode if Node has no ClassAlias and is not a product
			if(!item.ClassAlias && !item.isProduct){
				dojo.removeClass(node.iconNode,"Icon");
			}
			else{
				var iconSpriteName = epages.cartridges.de_epages.presentation.icon.getIconSpriteName(item.ClassAlias, IsVisibleContentView, item.isProduct);
				dojo.addClass(node.iconNode, "Sprite");
				dojo.removeClass(node.iconNode, iconSpriteName + "_inactive");
				dojo.addClass(node.iconNode, iconSpriteName);
			}
			if(IsVisibleContentView) {
				dojo.removeClass(node.contentNode,"NotVisible");
			}else {
				dojo.addClass(node.contentNode,"NotVisible");
			}
			item.persistentIconClass = node.iconNode.className;
		},

		changeVisibilityCurrent: function(){
			var node = this.lastFocused;
			if (node === undefined){
				return;
			}
			node.item.IsVisibleContentView = this.model.store.changeVisibility(node.item);
			this.setState(node,node.item.IsVisibleContentView);
			dojo.publish(this.id+'/changeCurrentVisibility',[node]);
		},

		_onStoreChangeVisibility: function(opt){
				var node = this._getNodeByObjectId(opt.item.objectId);
				var IsVisibleContentView = parseInt(opt.item.IsVisibleContentView);
				this.setState(node,IsVisibleContentView);
				if(node == this.lastFocused){
					dojo.publish(this.id+'/changeCurrentVisibility',[node]);
				}
		},
		currentItem: function(){
			return this.lastFocused.item;
		},

		onOpen: function(item,node){
			// add childNodes to childArray of item
			var childNodes = node.getChildren();
			var itemChildArray = node.item.children;
			for( var i=0,iLength=childNodes.length ; i<iLength ; i++ ){
				if(childNodes[i].item && childNodes[i].item.objectId){
					var childId = childNodes[i].item.objectId;
					if(!$A(itemChildArray).exists(childId)){
						node.item.children.push(childId);
					}
				}
			}
		},

		_onExpandoClick: function(/*Object*/ message){
			// summary: user clicked the +/- icon; expand or collapse my children.
			var node = message.node;

			// If we are collapsing, we might be hiding the currently focused node.
			// Also, clicking the expando node might have erased focus from the current node.
			// For simplicity's sake just focus on the node with the expando.

			if(node.isExpanded){
				this._collapseNode(node);
			}else{
				this._expandNode(node);
				this.setChildrenState(node);
			}
			//if a node with too many children was expanded the server gives an error code
			//check this code and show warning if necessary
			var item = this.model.store.fetchItemByIdentity(node.item.objectId);
			if(item.error && item.error == 'ERROR_TOO_MANY_CHILDREN'){
				this._showManyChildrenWarning(this.item.objectId);
			}
		},

		_showManyChildrenWarning: function(id){
			//summary: shows warning if selected item has too many children to show
			var currentObjectLink = '<br /><br /><a link class="DialogAction" style="font-weight:bold" onclick="window.location.href=\'?ObjectID='+id+'&ViewAction=MBO-ViewGeneral\'" >'+this._translation.get('OpenDatasheetView')+'</a>';
				dojo.publish("uimessage/show", [ this._translation.get('TooManyChildrenWarning'), this._translation.get('TooManyChildrenHint') + currentObjectLink, 'Dialog', {
					titleBar: this._translation.get('Notification'),
					typeClass: 'Notification'
				}]);
		}
	}
);