/*
	Copyright (c) 2006-2007, ePages GmbH
	All Rights Reserved.
*/
dojo.provide("epages.cartridges.de_epages.design.widget.Navigationelement");
dojo.require("epages.lang.array");
dojo.require("epages.lang.hash");
dojo.require("epages.string");
dojo.require("epages.widget.LocalizedWidget");
dojo.require("epages.event");
dojo.require("dijit.Menu");
dojo.require('epages.io.json');
dojo.require('epages.cartridges.de_epages.presentation.dragdrop');
dojo.require("dijit._Container");
dojo.require("epages.event");
dojo.require('epages.html');
dojo.require('epages.html.element');
dojo.require('epages.cartridges.de_epages.design.mcecontent');

epages.cartridges.de_epages.design.widget.Navigation = {
	dndHandler        : undefined,	// epages.cartridges.de_epages.presentation.dragdrop - drag and dro handler

	createElement : function (/*String*/navElementId, /*String*/styleId, /*String*/navBarAlias, /*String*/url, /*String*/navElAlign, /*Boolean*/positioning) {
		// summary:
		//			function to create a new widget
		// description:
		//			load template snippet, initalizes and insert the widget
		// navElementId:
		//			navigation element type id
		// styleId:
		//			ObjectID of current style
		// navBarAlias:
		//			alias of navbar e.g. "Right"
		// url:
		//			request url (default is '?')
		// navElAlign:
		//			alignment of new widget (default is 'left')
		// positioning:
		//			show/hide alignNode of new widget (default is 'false')

		if (url === undefined){
			url = '?';
		}
		if (navElAlign === undefined){
			navElAlign = 'left';
		}
		if (navElAlign!== 'left') {
			navElAlign = 'right';
		}
		var j = new epages.io.Json();
		var output = j.loadSync(url, {
			ChangeAction: 'AddNavElement',
			ChangeObjectID: styleId,
			NavElementID: navElementId,
			NavBarAlias: navBarAlias,
			Alignment: navElAlign.charAt(0).toUpperCase() + navElAlign.slice(1),
			ViewAction: 'JSONNavBarElementSnippet',
			IsEditorNavElements: 1,
			IsEditorModeEnabled: 1
		});
		if(output.error){
			if(output.error.data && output.error.data.Errors) {
				//highjack translations
				hl = epages.cartridges.de_epages.design.widget.Navigationelement.prototype.translate("ErrorCreateNewPageElement");
				tb = epages.cartridges.de_epages.design.widget.Navigationelement.prototype.translate("CreateNewPageElement");
				dojo.publish("uimessage/showErrors", [hl, tb,	output.error.data.Errors]);
			}
			return false;
		}	else if(output.data){
			var navbar = epages.NavBars[output.data.navbarid][3];
			var doc = navbar.ownerDocument;
			var e = doc.createElement("div");
			e.innerHTML = output.data.snippet;
			e.id = 'Element' + output.data.id;
			epages.html.disableHrefsAndActions(e);

			epages.cartridges.de_epages.design.widget.Navigation.getNavBarDelete(doc).appendChild(e);

			var scriptTags = e.getElementsByTagName('script');
			for(var i = 0, iLength = scriptTags.length; i < iLength; i++){
				//eval is needed to execute script for navigation elements that use jquery
				//doc.defaultView is needed to change context of eval to the context of the iframe
				//by using plain eval or new Function the context for the script would be wrong
				doc.defaultView.eval(scriptTags[i].innerHTML);
			}

			var win = (doc.parentWindow) ? doc.parentWindow : doc.defaultView;

			var widgetClass = 'epages.cartridges.de_epages.design.widget.Navigationelement';

			if(win.epages.vars.NavigationElementWidgetTypes) {
				if(win.epages.vars.NavigationElementWidgetTypes[navElementId]) {
					widgetClass = win.epages.vars.NavigationElementWidgetTypes[navElementId];			//catch widget type
					win.dojo["require"](widgetClass);
				}
			}
			widgetClass='win.'+widgetClass;

			var w = new(eval(widgetClass))({
				elementId: e.id,
				objectId: output.data.id,
				navbar: 'Delete',
				isCustomizable: output.data.isCustomizable,
				position: output.data.position,
				alignment: navElAlign,
				doc : doc,
				positioning: positioning
			});
			w.setNavBar(output.data.navbarid);
			return w;
		}
	},
	getNavBarDelete: function( doc ){
		var node = this.getNavBarDelete.node || ( this.getNavBarDelete.node = $('NavBarDelete',doc) );

		if ( !node ) {
			node = this.getNavBarDelete.node = doc.createElement("div");

			node.id = 'NavBarDelete';
			node.style.display = 'none';

			doc.getElementsByTagName("body")[0].appendChild(node);
		}

		return node;
	}
};

dojo.declare(
	"epages.cartridges.de_epages.design.widget.Navigationelement",
	[epages.widget.LocalizedWidget,dijit._Container],
	{
		/**
		 * public properties
		 */
		objectId            : '',           // String - epages objectid of navigation element
		position            : '',           // String - current position in navbar
		alignment						: 'left',				// String - 'left' or 'right' in navbar.
		left 								: 'auto',				// String - pixel value or 'auto' for css property 'left'.
		top 								: 'auto',				// String - pixel value or 'auto' for css property 'top'.
		positioning					: false,				// Boolean - indicates whether to show the alignment/positioning tool.
		navbar              : '',           // String - current navbar identifier
		orientation         : '',           // String - current navbar orientation e.g. UpDown
		elementId           : '',           // String - id of the navigationelement domnode
		storeRoot           : epages.vars.StoreRoot,	// [readonly] String - epages store root path
		undoWidgetId        : 'undoWidget', // String - id of undo widget
		isCustomizable      : '',           // Boolean - indicates weather the navigation element has an edit dialog or not
		url                 : '?',          // String - request url string
		languageId          : epages.vars.Locale.languageId,  // string - current language id
		emptyString         : '',           // String - will be displayed in empty customizable html areas
		doc                 : undefined,    // document - navigation elements document
		reloadOnOrientationChange: false,   // Boolean - indicates weather the html code of an navigation element needs to be reloaded after changing the navbar (some navigation elements use a different html code base for navigation bars with different orientations)
		nameOrAlias         : "",           // String - #NameOrAlias
		_widgetsA           : [],           // Array - list of navelement widgets for each navbar('s left part) (prototype Array)
		_widgetsARight      : [],						// Array - list of navelement widgets for each navbar's right part (prototype Array). Only for horizontal navbars!
		_htmlUndo           : undefined,    // epages.cartridges.de_epages.presentation.widget.Undobuttons - html undo object to register changes
		_inputs             : undefined,    // domnode[] - list of editor inputs in edit dialog (name starts with editor_)
		positionNode        : undefined,  	// domnode - input field to enable undo for position
		alignmentNode				: undefined,		// domnode - input field to enable undo for alignment inside navbar
		leftNode						: undefined,		// domnode - input field to enable undo for setting css property 'left'
		topNode							: undefined,		// domnode - input field to enable undo for alignment setting css property 'top'
		navbarChangeNode    : undefined,    // domnode  - input field to enable undo for navbar
		navElementNode      : undefined,    // domnode - node of the original navigation element
		_navElementNodeCache: undefined,    // hash - caches elementnodes for different navelement views (UpDown/LeftRight)
		_deleteConfirmation : false,        // [readonly] Boolean - flag that indicates weather the delete confirmation dialog will be shown or not (flag source: top.epages.vars.SessionUserDeleteConfirmation)

		/**
		 * widget properties
		 */
		imagePath       : epages.themeUrl('images'),   // String - path to widget image folder
		templatePath    : dojo.moduleUrl('epages.cartridges.de_epages.design.widget','templates/Navigationelement.html'), // String - path to widget template
		translationName : dojo.moduleUrl('epages.cartridges.de_epages.design.widget','templates/translation'), // String - path to widget translation

		loadNavBarElement : function (navElementId, styleId, navBarAlias, url) {
		// summary: get and insert navbar element snippet
			if (url === undefined){
				url = '?';
			}
			var j = new epages.io.Json();
			var output = j.loadSync(url, {
				ObjectID: styleId,
				NavElementID: navElementId,
				NavBarAlias: navBarAlias,
				ViewAction: 'JSONNavBarElementSnippet',
				IsEditorNavElements: 1,
				IsEditorModeEnabled: 1
			});

			if(output.error){
				return false;
			} else if(output.data){
				var navbar = epages.NavBars[output.data.navbarid][3];
				var doc = navbar.ownerDocument;
				var e = doc.createElement("div");
				e.innerHTML = output.data.snippet;
				e.id = 'Element' + output.data.id;
				epages.html.disableHrefsAndActions(e);
				return e;
			}
		},

		elementNode : function () {
			// summary:
			//			returns the element domnode which will be moved via dnd
			// description:
			//   		the domnode that will be moved can be the widgets root dom
			//			node or the parent node of the dom node (td-tag)
			return this.orientation == 'UpDown' ? this.domNode : this.domNode.parentNode;		// dom node
		},

		navbarNode : function () {
			// summary:
			//			returns the container node for dnd elements
			return this.elementNode().parentNode;
		},

		elementNodes: function () {
			// summary:
			//			returns all draggable nodes in the current navigation bar
			return dojo.filter(this.navbarNode().childNodes, function (el) { // DomNode[]
				return el.nodeType == 1;
			});
		},

		siblingWidgets: function () {
			// summary:
			//			returns all draggable navbar widgets in the current navigation bar
			//			with *left* alignment
			if (this._widgetsA && this._widgetsA[this.navbar]) {
				return [].concat(this._widgetsA[this.navbar]);
			}
			return []
		},

		siblingWidgetsRight: function () {
			// summary:
			//			returns all draggable navbar widgets in the current navigation bar
			//			with *right* alignment
			if (this._widgetsARight && this._widgetsARight[this.navbar]) {
				return [].concat(this._widgetsARight[this.navbar]);
			}
			return []
		},

		currentIndex: function () {
			// summary: returns the navigation bar index of the element
			return $A(this._widgetsA[this.navbar]).find(this); // Integer
		},

		existsPosition: function (/*integer*/ position, /*integer*/ navbarid, /*string*/ alignment) {
		// summary: check weather the specified position exits in specified navbar
			if (navbarid === undefined){
				navbarid = this.navbar;
			}
			if (alignment === undefined){
				alignment = this.alignment;
			}
			var a = $A(this['_widgetsA' + ((this.alignment === 'right') ? 'Right' : '')][navbarid]).grep(function (el) {
				return parseInt(el.positionNode.value) == position; // Boolean
			});
			return a.length > 0; // Boolean
		},

		postMixInProperties: function() {
		// summary: prepare defaults
			this.inherited("postMixInProperties", arguments);
			if(this.doc === undefined || this.doc == ''){
				this.doc = document;
			}
			if (typeof this.isCustomizable == 'string') {
				this.isCustomizable = epages.string.toBoolean(this.isCustomizable);
			} else {
				this.isCustomizable = this.isCustomizable == 0 ? false : true;
			}
			this._inputs = [];
			this.emptyString = '- '+this.translate('ClickToChangeContent')+' -';
			if(top.epages.vars.SessionUserDeleteConfirmation == 1){
				this._deleteConfirmation = true;
			}
		},

		postCreate  : function() {
			// summary:
			//			prepare navelement widget nodes / events / ...
			this.inherited("postCreate", arguments);

			this.positionNode = this.doc.createElement("input");
			this.positionNode.type  = 'hidden';
			this.positionNode.name  = this.objectId + ':Position';
			this.positionNode.value = this.position;

			this.alignmentNode = this.doc.createElement("input");
			this.alignmentNode.type  = 'hidden';
			this.alignmentNode.name  = this.objectId + ':Alignment';
			this.alignmentNode.value = this.alignment.charAt(0).toUpperCase() + this.alignment.slice(1);

			this.leftNode = this.doc.createElement("input");
			this.leftNode.type  = 'hidden';
			this.leftNode.name  = this.objectId + ':Left';
			this.leftNode.value = this.left;

			this.topNode = this.doc.createElement("input");
			this.topNode.type  = 'hidden';
			this.topNode.name  = this.objectId + ':Top';
			this.topNode.value = this.top;

			this.navbarChangeNode = this.doc.createElement("input");
			this.navbarChangeNode.type  = 'hidden';
			this.navbarChangeNode.name  = this.objectId + ':NavBar';
			this.navbarChangeNode.value = this.navbar;

			// IE fix onchange event
			if (epages.Browser.engine == 'MSIE') {
				this.doc.getElementsByTagName('body')[0].appendChild(this.positionNode);
				this.doc.getElementsByTagName('body')[0].appendChild(this.navbarChangeNode);
				this.doc.getElementsByTagName('body')[0].appendChild(this.alignmentNode);
				this.doc.getElementsByTagName('body')[0].appendChild(this.leftNode);
				this.doc.getElementsByTagName('body')[0].appendChild(this.topNode);
			}

			epages.cartridges.de_epages.design.widget.Navigation.getNavBarDelete(this.doc);

			if (epages.NavBars !== undefined) {
				epages.NavBars['Delete'] = ['Delete', 'UpDown', 'Delete'];
			}
			if (!this.isCustomizable){
				this.editNode.style.display = 'none';
			}
			if (!this.positioning) {
				dojo.query(this.alignNode).orphan();
			}

			// get undo object for add inputs
			if (this._htmlUndo === undefined) {
				var undoWidget = $$(this.undoWidgetId);
				if (undoWidget === undefined) {
					console.warn('undo widget not found in '+this.declaredClass +'. (undoWidgetId = ' + this.undoWidgetId + ')');
				} else {
					this._htmlUndo = undoWidget.getUndoObject();
				}
			}

			// move navelement in my widget
			var element = $(this.elementId,this.doc);
			if (element) {
				$E(this.replaceNode.parentNode).replaceChild(element,this.replaceNode);
			} else {
				console.warn("widget Navigationelement can't find element:" + this.elementId);
			}

			var child = element.firstChild;
			while(child != null && this.navElementNode === undefined) {
				if(child.nodeType==1) {
					this.navElementNode = child;
				}
				child=child.nextSibling;
			}
			if(this.navElementNode){
				this._adjustGeomtry(this.navElementNode);
			}


			// initialize navbar
			if (this.alignment === 'right') {
				if (this._widgetsARight[this.navbar] === undefined){
					this._widgetsARight[this.navbar] = [];
				}
				this._widgetsARight[this.navbar].push(this);
			} else {	// standard = left alignment
				if (this._widgetsA[this.navbar] === undefined){
					this._widgetsA[this.navbar] = [];
				}
				this._widgetsA[this.navbar].push(this);
			}

			if (this._htmlUndo) {
				this._htmlUndo.setDefaultValue(this.positionNode);
				this._htmlUndo.setDefaultValue(this.navbarChangeNode);
				this._htmlUndo.setDefaultValue(this.alignmentNode);
				this._htmlUndo.setDefaultValue(this.leftNode);
				this._htmlUndo.setDefaultValue(this.topNode);
			}

			// add global drag and drop handler if it isn't already added
			if(epages.cartridges.de_epages.design.widget.Navigationelement.dndHandler === undefined) {
				epages.cartridges.de_epages.design.widget.Navigationelement.dndHandler=$DND("NavElements", [], $('Content'));
			}

			var win = (this.doc.parentWindow) ? this.doc.parentWindow : this.doc.defaultView;

			var dndHandler = win.epages.cartridges.de_epages.design.widget.Navigationelement.dndHandler;
			// register widget as drag and drop element
			dndHandler.addElement({
				clickNode: this.dndNode,
				moveNode: this.domNode,
				widget: this,
				onDropInList: function(opt) {
					this.widget.onDropInList(opt);
				},
				onDrop: function () {
					this.widget._resetPosition();
				},
				forceSize: true
			});

			// connect events
			this.connect(this.deleteNode, 'onclick', 'onclickDeleteNode');
			if (this.isCustomizable){
				this.connect(this.editNode, 'onclick', 'onclickEditNode');
			}

			if (epages.NavBars !== undefined) {
				this.connect(this.navbarChangeNode, 'onchange', 'onchangeNavbarChangeNode');
				this.orientation = epages.NavBars[this.navbar][1];
			}

			// In advanced and quick design we reset
			// the *top* and *left* css attributes set by SF-Style.StyleSheet.css
			// and do the *top* and *left* positiong via javascript i.e. the style attribute.
			// This way we can easily update these values without having to regenerate the CSS.
			// see EPG-26482: Possibility to float page elements individually

			// reset top and left css
			var navbarelem = dojo.query('> [id^="Element"]> [class*="NavBarElement"]', this.contentNode)[0];

			if(navbarelem){
				dojo.style(navbarelem, 'left', 'auto');
				dojo.style(navbarelem, 'top', 'auto');
			}

			// init top and left css
			dojo.style(this.domNode, 'left', this.left === 'auto' ? null : this.left + 'px');
			dojo.style(this.domNode, 'top', this.top === 'auto' ? null : this.top + 'px');

			// prepare for orientation change (differnet views of some navelements)
			this.reloadOnOrientationChange = (this.navElementNode && this.navElementNode.className.match("ReloadOnOrientationChange")) ? true : false;
			this._navElementNodeCache = $H();
			this._navElementNodeCache.set(this.orientation, this.navElementNode);
			this.connect(this.positionNode, 'onchange', 'onchangePositionNode');
			this.connect(this.alignmentNode, 'onchange', 'onchangeAlignmentNode');
			this.connect(this.leftNode, 'onchange', 'onchangeLeftNode');
			this.connect(this.topNode, 'onchange', 'onchangeTopNode');
		},

		setNodePosition: function (position) {
			// summary:
			//			set new position
			this.positionNode.value = position;
			if (this._htmlUndo){
				this._htmlUndo.addInput(this.positionNode);
			}
		},

		onchangeLeftNode : function (evt) {
			dojo.stopEvent(evt);
			this.left = this.leftNode.value;
			dojo.style(this.domNode, 'left', this.left === 'auto' ? null : this.left + 'px');
			if (this._htmlUndo){
				this._htmlUndo.addInput(this.leftNode);
			}
		},

		onchangeTopNode : function (evt) {
			dojo.stopEvent(evt);
			this.top = this.topNode.value;
			dojo.style(this.domNode, 'top', this.top === 'auto' ? null : this.top + 'px');
			if (this._htmlUndo){
				this._htmlUndo.addInput(this.topNode);
			}
		},

		onchangeAlignmentNode: function (evt) {
			// summary:
			//			set new alignment
			//			really, this is only ever called by the htmlundo widget.
			dojo.stopEvent(evt);
			this.setNavBar(this.navbar, true, this.orientation,this.alignmentNode.value.toLowerCase());
		},

		onchangePositionNode: function (evt) {
			// summary:
			//			called when position node fired a change / adjusts _widgetsA
			//			and dom node postion
			// tags:
			//			callback
			dojo.stopEvent(evt);

			// remove current (changed)
			var position = parseInt(this.positionNode.value);
			var waArray = $A(this['_widgetsA' + ((this.alignment === 'right') ? 'Right' : '')][this.navbar]);
			var oldlength = waArray.length;
			waArray.remove(waArray.find(this));

			// add changed on right place
			var wa = waArray.grep(function (el) {
				return parseInt(el.positionNode.value) <= position;
			}).concat(this, waArray.grep(function (el) {
				return parseInt(el.positionNode.value) > position;
			}));
			if (oldlength != wa.length){
				console.warn('Widget Navigationelement list changed!! oldlength:' + oldlength +'!= new length:'+ wa.length);
			}
			this['_widgetsA' + ((this.alignment === 'right') ? 'Right' : '')][this.navbar] = wa;

			// correct dom nodes
			for( var i=0,l=wa.length ; i<l ; i++ ) {
				wa[i].navbarNode().appendChild(wa[i].elementNode());
				// renumber classnames
				var className = wa[i].navElementNode.className;
				var className = className.replace(/NavBarElement\d*/,"NavBarElement"+i);
				wa[i].navElementNode.className = className;
			}

			this.adjustNewGhostEol();
		},

		onclickDeleteNode: function (evt) {
		// summary:
		//			called when delete node was clicked / shows a delete confirmation dialog
		// tags:
		//			callback
			dojo.stopEvent(evt);
			if(this._deleteConfirmation){
				var me = this;
				epages.topDojo.publish("uimessage/show", [ this.translate('AcceptDeletePageElement'), "", 'Dialog', {
					titleBar: this.translate('DeletePageElement'),
					typeClass: 'Confirmation',
					buttons: [{
						label: '{Delete}',
						cssClass: 'Active',
						onclick: function() {
							me.deleteNavigationElement();
							this._modalDialogWidget.hide();
						}
					},{
						label: '{Cancel}',
						onclick: function() { this._modalDialogWidget.hide(); }
					}]
				}
				]);
			}	else {
				this.deleteNavigationElement();
			}
		},

		deleteNavigationElement: function(){
		// summary:
		//			move navigation element into delete navigation bar
			this.setNavBar('Delete', false);
			dojo.publish("Navigationelement/DeleteFinished", []);
		},

		setNavBar: function (navbarid, pushOnEnd, orientation, alignment) {
		// summary:
		//			move navigation element into specified navigation bar
			if (this.navbar == navbarid && this.alignment == alignment){
				return;
			}
			if (alignment === undefined) {
				alignment = this.alignment;
			}
			if (pushOnEnd === undefined){
				pushOnEnd = true;
			}
			if (epages.NavBars !== undefined) {
				orientation = epages.NavBars[navbarid][1];
			}

			this._resetPosition();

			// reload element view for different orient (if necessary)
			if(orientation !== this.orientation && this.reloadOnOrientationChange) {
				var el = this._navElementNodeCache.get(orientation);
				if(el === undefined) {
					el = this.loadNavBarElement(this.elementId, this.objectId, epages.NavBars[navbarid][2]);
					if(el !== false){
						// chache element
						this._navElementNodeCache.set(orientation, el);
					}else{
						console.warn('Could not load different view of navigation element');
					}
				}
				// replace domnode
				this.navElementNode.parentNode.replaceChild(el, this.navElementNode);
				// assign new domnode to object property
				this.navElementNode = el;
			}

			var navbar = $('NavBar' + ((navbarid === 'Delete') ? navbarid : (navbarid + ((alignment === 'right') ? 'Right' : ''))), this.doc);
			if (navbar == null && alignment === 'right') {
				console.warn('Element NavBar' + navbarid + ' has no right part.');
				navbar = $('NavBar' + navbarid, this.doc);
				if (navbar) {this.alignment=alignment;}
			}
			if (navbar == null) {
				console.error('Element NavBar' + navbarid + ' not found.');
				return;
			}
			// add to new list
			if (this._widgetsA[navbarid] === undefined){
				this._widgetsA[navbarid] = [];
			}
			if (this._widgetsARight[navbarid] === undefined){
				this._widgetsARight[navbarid] = [];
			}
			var wa = this['_widgetsA' + ((alignment === 'right') ? 'Right' : '')][navbarid];
			var position = parseInt(this.positionNode.value);
			var positionChanged = false;
			if (wa.length) {
				if (!pushOnEnd && this.existsPosition(position, navbarid, this.alignment)){
					pushOnEnd = true;
				}
				if (pushOnEnd) {
					var i = wa.length;
					var last = wa[i - 1];
					var lastPos = parseInt(last.positionNode.value);
					if (position <= lastPos) {
						position = lastPos + 10;
						positionChanged = true;
					}
				}
			}

			// change dom nodes
			if (this.orientation == orientation) {
				$E(navbar).appendChild(this.elementNode());
			} else {
				if (orientation == 'LeftRight') {
					// move from div to tr (add td)
					var td = this.doc.createElement('td');
					$E(navbar).appendChild(td);
					td.appendChild(this.elementNode());
				} else {
					// move from tr to div (remove td)
					var td = this.elementNode();
					$E(navbar).appendChild(this.domNode);
					td.parentNode.removeChild(td);
				}
				this.orientation = orientation;
			}
			if (positionChanged){
				this.positionNode.value = position;
			}
			this.navbarChangeNode.value = navbarid;

			// remove from old list and add to new
			var waOld = this['_widgetsA' + ((this.alignment === 'right') ? 'Right' : '')][this.navbar];
			waOld.splice($A(waOld).find(this), 1);
			wa.push(this);
			this.navbar = navbarid;


			if(!pushOnEnd) {
				// move to correct position (enables buttons also)
				epages.event.fire(this.positionNode,'change');
			}

			// set html elements for undo
			if (this._htmlUndo) {
				if (positionChanged){
					this._htmlUndo.addInput(this.positionNode);
				}
				this._htmlUndo.addInput(this.navbarChangeNode);
					if (this.alignment !== alignment) {
					this.alignment = alignment;
					this.alignmentNode.value = alignment.charAt(0).toUpperCase() + alignment.slice(1);
					this._htmlUndo.addInput(this.alignmentNode);
				}
			}
			dojo.publish('droplistNavBar'+this.navbar+'/change', []);
			if (this.alignment === "right") {
				dojo.publish('droplistNavBar'+this.navbar + 'Right' + '/change', []);
			}



			this.adjustNewGhostEol();
			this.alignment = alignment;
		},

		adjustNewGhostEol: function() {
		// summary: correct position of new ghost (always last domnode)
			var navbarNodes=$('NavBar' + ((this.navbar === 'Delete') ? this.navbar : (this.navbar + ((this.alignment === 'right') ? 'Right' : ''))), this.doc).childNodes;
			for(var el in navbarNodes){
				if(navbarNodes[el] !== undefined && navbarNodes[el].className=="Ghost New"){
					$('NavBar' + ((this.navbar === 'Delete') ? this.navbar : (this.navbar + ((this.alignment === 'right') ? 'Right' : ''))), this.doc).appendChild(navbarNodes[el]);
				}
			}
		},

		onchangeNavbarChangeNode: function (evt) {
		// summary:
		//			called when NavbarChangeNode (idicates an navifation bar change)
		//			changed / adjusts elements navbar assignment and publish droplist
		//			change messages
		// tags:
		//			callback
			dojo.stopEvent(evt);

			this.setNavBar(this.navbarChangeNode.value, false);
			// publish change event to old and new droplists
			if(this.domNode.ep_droplistid) {
				dojo.publish('droplist'+this.domNode.ep_droplistid+'/change', []);
			}
			dojo.publish('droplistNavBar'+this.navbar + '/change', []);
			if (this.alignment === "right") {
				dojo.publish('droplistNavBar'+this.navbar + 'Right' + '/change', []);
			}
			this.domNode.ep_droplistid='NavBar'+this.navbar;
		},

		onDropInList: function(/*Object*/options) {
		// summary:
		//			called by droplist handler / adjust new positon of navigation alement
		// tags:
		//			callback
			var newNavbarid = options.listObject.options.navbarid;
			var newAlignment = options.listObject.options.alignment;
			//var newNavbarid = options.listContainer.options.navbarid;
			var successor = options.insertBefore;

			var isNewNavbar = this.navbar !== newNavbarid;
			if(isNewNavbar || (this.alignment !== newAlignment)) {
				this.setNavBar(newNavbarid, isNewNavbar, undefined,  newAlignment);  // always push to end insert
			}

			var wa = this['_widgetsA' + ((newAlignment === 'right') ? 'Right' : '')][newNavbarid];

			if(successor != null && successor.className!="Ghost New") {
				var successorFound=false;
				for(var w in wa) {
					if(wa[w].domNode === successor) {
						var posPredecessor = (wa[w-1]) ? parseInt(wa[w-1].positionNode.value) : 0;
						var posSuccessor = parseInt(wa[w].positionNode.value);
						var posSuperSuccessor = (wa[w+1]) ? wa[w+1] : parseInt(wa[w].positionNode.value) + 10;
						var posDistance = parseInt((posSuperSuccessor-posPredecessor) / 3);
						var newPosDropped = posPredecessor + posDistance;
						var newPosSuccessor = posPredecessor + 2 * posDistance;
						var successorPositonNode = wa[w].positionNode;

						successorPositonNode.value = newPosSuccessor;
						epages.event.fire(successorPositonNode, 'change');

						this.positionNode.value = newPosDropped;
						epages.event.fire(this.positionNode, 'change');

						if (this._htmlUndo) {
							this._htmlUndo.addInput(successorPositonNode);
							this._htmlUndo.addInput(this.positionNode);
						}

						successorFound=true;
						break;
					}
				}
				if(!successorFound) {
					console.warn("Navigationelement.onDropInList: successor dom node not found");
				}
			} else if(!isNewNavbar) { // insert as last element
					var last = wa[wa.length - 1];
					var lastPos = parseInt(last.positionNode.value);
					this.positionNode.value = lastPos + 10;

					epages.event.fire(this.positionNode, 'change');

					if (this._htmlUndo){
						this._htmlUndo.addInput(this.positionNode);
					}
			}

			// fire click event to select navbar
			epages.event.fire($('NavBar'+this.navbar,this.doc), 'click');

			dojo.publish("Navigationelement/onDropInListFinished", []);
		},

		onclickEditNode: function (evt) {
		// summary:
		//			show dialog for customizable navigation elements
		// tags:
		//			callback
			if (evt !== undefined){
				 dojo.stopEvent(evt);
			}
			if (this._editorWidget === undefined) {   // create new dialog
				this.createEditDialog();
				this.initEditDialog();
			} else {                                  // dialog is already up and running
				this.resetEditDialogInputValues();
			}
			this.onbeforeShowDialog();
			this._editorWidget.show();
		},

		createEditDialog: function() {
		// summary:
		//			create edit dialog for customizable navigation elements
		// description:
		//  		load dialog data and instanciates diaolg within a modal dialog widget
		// tags:
		//			protected

			// load dialog template
			dojo.require('epages.io.json');
			var json = new epages.io.Json();
			var result = json.loadSync(this.url, {
				'ViewAction': 'JSONSnippet',
				'TemplateAction': 'EditSnippet',
				'TemplateLanguageID': this.languageId,
				'ObjectID': this.objectId
			});

			// create and setup dialog
			var _navigationElementWidget = this;

			// Create an undo stack for dialogs
			top.epages.html.UnDo.prototype.undoNavigationElementWidgetStack.push(_navigationElementWidget);

			top.dojo["require"]('epages.widget.Modaldialog');
			var newDiv = top.document.createElement('div');												// dialog insert point
			top.document.getElementsByTagName('body')[0].appendChild(newDiv);
			var nameOrAlias = this.nameOrAlias != "" ? ": "+this.nameOrAlias : "";

			this._editorWidget = new top.epages.widget.Modaldialog({
				options:{
					title : _navigationElementWidget.translate('EditNavElement')+nameOrAlias,
					content: result.data.snippet,
					scroll: 'hidden'
				},
				buttons: [{
					label: _navigationElementWidget.translate('Apply'),
					cssClass: "Active",
					onclick: function() {
					// apply function - fire change on hidden element node
						this._modalDialogWidget.hide();
						_navigationElementWidget.applyEditorDialogInputValues();
						dojo.publish("Navigationelement/EditFinished", []);
					}
				}, {
					label: _navigationElementWidget.translate('Cancel'),
					onclick: function() {
					//cancel action, just hide dialog
						this._modalDialogWidget.hide();
						_navigationElementWidget.resetEditDialogInputValues();
					}
				}]
			}, newDiv);
		},

		initEditDialog: function() {
		// summary:
		//			called after edit dialog was created
		// description:
		//			registers all relevant input elements (inputs starting with "editor_" followed by ObjectID:Attributname:LanguageID e.g. editor_12345:MyAttribute:1)
		// tags:
		//			protected
			var undo = $$(this.undoWidgetId).undoObject;
			var _this = this;
			var iterator = dojo.hitch(this, function (el) {
			// parse dialog inputs, build a copy in parent window and register them to undo widget

				if (el.name === undefined || !el.name.match(/^editor_/)){
					return;		// skip unnamed inputs and inputs wich do not start with "editor_"
				}
				var hid = el.parentNode.ownerDocument.createElement('input');				// create a hidden input element in main window
				hid.name =el.name.substr(7);																				// cut "editor_" away
				hid.type ='hidden';
				hid.value = $E(el).get();																						// e.g. <input type="hidden" name="12345:MyAttribute" value="MyValue" />

				if(el.getAttribute("ep_noundo")=="1") {
					hid.setAttribute("ep_noundo","1");
				}

				var ep_publishmessage = el.getAttribute("ep_publishmessage");
				el.parentNode.appendChild(hid);
				_this._inputs.push({																								// save nodes to this._inputs array
					'editorNode' : el,																								// editor node (edit node in dialog) -> format example: <inupt type="hidden" name="editor_1234:Logo:1" value="myvalue" />
					'hiddenNode' : hid,																								// hidden input node (real value container for undo widget) -> <input type="hidden" name="1234:Logo::1" value="myvalue" />
					'ep_publishmessage' : ep_publishmessage														// pass input message identifier
				});
				undo.registerInput(hid);																						// register the hidden input node to undo widget
				epages.topDojo.connect(hid, 'onchange', _this, 'setPreview');				// connect inputs to preview function
			});

			// make copy because getElementsByTagName will be change during the iterator
			var aCopy = [];
			dojo.forEach(this._editorWidget.domNode.getElementsByTagName("input"), function (el) { aCopy.push(el); });
			dojo.forEach(aCopy, iterator);
			dojo.forEach(this._editorWidget.domNode.getElementsByTagName("select"),   iterator);
			dojo.forEach(this._editorWidget.domNode.getElementsByTagName("textarea"), iterator);
		},

		onbeforeShowDialog: function() {
		// summary:
		//			override function - called before dialog widget is shown
		// tags: callback extension protected
		},


		applyEditorDialogInputValues : function() {
		// summary:
		//			apply editor inputs (this._inputs) to hidden inputs (data storage)

			var _this = this;

			// set timeout because CKE needs some time to write back WYSIWYG data
			window.setTimeout(function(){
				dojo.forEach(_this._inputs, function (el) {
					var value = $E(el.editorNode).get();

					if(el.editorNode.type=='radio' || el.editorNode.type=='checkbox'){ // special handling for radio buttons
						if(el.editorNode.checked == true){
							el.hiddenNode.value = value;
							_this.onbeforePreview(el.hiddenNode);
							epages.event.fire(el.hiddenNode,'change');
						}else{
				            var topLength = top.document.getElementsByName(el.hiddenNode.name).length;
				            var selfLength = document.getElementsByName(el.hiddenNode.name).length;

				            if(((topLength!==undefined)&&(topLength>1)) || ((selfLength!==undefined)&&(selfLength>1))){
				            	el.hiddenNode.value = "";
				            }

				        }
					} else if (el.hiddenNode.value != value) {											// fire only if value is different
						el.hiddenNode.value = value;
						_this.onbeforePreview(el.hiddenNode);
						epages.event.fire(el.hiddenNode,'change');
					}
				}, _this);
			}, 300);
		},

		resetEditDialogInputValues: function() {
		// summary:
		//			reset input values / set values from hiddenNode
		//			(data storage to editor inputs (this._inputs)
		// tags:
		//			protected

			dojo.forEach(this._inputs, function (el) {
				var formElement = $E(el.editorNode);
				var elValue = formElement.get();
				var hiddenValue = el.hiddenNode.value;
				if(elValue != hiddenValue) {		// set value only if changed
					formElement.set(hiddenValue);
					formElement.callOnChange();
				}
			});
		},

		onbeforePreview: function(/*domnode*/ inputNode) {
		// summary:
		//			called before setPreview (change is fired on input node) -
		//			publishes a message on all input that have specified a message
		//			identifier (ep_publishmessage)
		// description:
		//			You may override this function but don't forget to call
		//			this.inherited("onbeforePreview", arguments);
		// inputNode:
		//			input node that has changed in dialog
		// tags:
		//			callback protected extension
			if(inputNode['ep_publishmessage']) {																// publish input specific message before change is fired, pass input node
				dojo.publish(inputNode['ep_publishmessage']+'/beforeChangeFired', [inputNode]);
			}
		},

		setPreview: function(evt) {
		// summary:
		//			update navigation element preview (called onchange: input node)
		// description:
		//      	Update content (texts / file url) of displayed naviagtion elements.
		//      	format example preview nodes: <img id="eid_1234:Logo:1" src="myurl" />
		// tags:
		//			callback protected
			var el = evt.target;																					// get input node (changed content)
			var node = $('eid_' + el.name, this.domNode.ownerDocument);		// get target node
			if (node) {
				var value = el.value == '' ? this.emptyString : el.value;		// get value;
				if(node.nodeName.match(/input|textarea|select/i)) {					// set value to form fields
					node.value = value;
				} else if(node.nodeName.match(/img/i)) {										// set value to image
					node.src=el.value;
				} else {																										// set value as html content
					node.innerHTML = el.value == '' ? this.emptyString : el.value;
					node.innerHTML = epages.cartridges.de_epages.design.MceContent.prototype.string2Preview(node.innerHTML);
					epages.html.disableHrefsAndActions(node);
					this._adjustGeomtry(node);
				}
				jQuery('body').trigger('updatepreview');
			} else {
				// no updates
				console.warn("node '%s' not found, possible not in template ("+this.declaredClass+")", 'eid_' + el.name);
			}
		},

		_adjustGeomtry: function(node) {
		// summary:
		//			adjust gemoetry of the original navigation element / force minimal size
		// tags:
		//			protected
			dojo.removeClass(node, "ForceMinSize");
			var cn = node.className;
			if((node.clientWidth < 11 && node.offsetWidth < 11 ||
					node.clientHeight < 11 && node.offsetHeight < 11) &&
					cn.match("NavigationText")){
					dojo.addClass(node, "ForceMinSize");
			}
		},

		_resetPosition: function() {
		// summary:
		//			reset *top* and *left* values to "auto", if necessary.
		// tags:
		//			protected
			if (this.left !== 'auto') {
				this.leftNode.value = 'auto';
				epages.event.fire(this.leftNode, 'change');
			}
			if (this.top !== 'auto') {
				this.topNode.value = 'auto';
				epages.event.fire(this.topNode, 'change');
			}
		},



		// dojoAttachEvent
		mouseenter_ButtonAndMetainfo: function() {
		// summary:
		//			show ButtonAndMetaInfo layer
		// tags:
		//			callback protected
			var el= this.elementNode();
			if(el && !epages.cartridges.de_epages.design.widget.Navigation.dndHandler) {
				dojo.addClass(el, "SetOver");
			}
		},

		mouseleave_ButtonAndMetainfo: function(evt) {
		// summary:
		//			hide ButtonAndMetaInfo layer
		// tags:
		//			callback protected
			var el_t = evt.target;
			var el_c = evt.currentTarget;
			var el= this.elementNode();
			if(el && el_t === el_c){
				dojo.removeClass(this.elementNode(), "SetOver");
			}
		}
	}
);