dojo.provide("epages.widget.Elementlist");
dojo.require("epages.widget.Elementlistitem");
dojo.require('epages.lang.array');
dojo.require('dijit._Container');

dojo.declare("epages.widget.Elementlist", [dijit._Widget,dijit._Templated,dijit._Container], {

		/**
		 * public properties
		 */
		templatePath     : dojo.moduleUrl('epages.widget','templates/Elementlist.html'),
		listClassName:      'ElementList',
		widgetElementType:  "epages.widget.Elementlistitem",
		multiSelect:        'false',
		objectId:           '',
		onselect:           '',
		children:           [],
		store:              undefined,
		pagging:            false,
		paggingQuantity:    20,

		eventNames:         undefined,
		eventNamesDefault: {
			afterListCreate:  'afterListCreate',
			afterSetChildren: 'afterSetChildren',
			select:           'select',
			deselect:         'deselect'
		},

		selectTypes:{
			SINGLE: 'SINGLE', // no modification key
			ADD:    'ADD',    // CTRL key
			LIST:   'LIST'    // SHIFT key
		},

		/**
		 * private properties
		 */
		_lastSelectedItem:   undefined,
		_allChildren: [],
		_pagger: {
			currentVisibleChildren : [],
			currentPage : 0,
			maxPage: 0
		},

		postMixInProperties: function(){
			this.pagging = epages.string.toBoolean(this.pagging);
		},

		adjustEventNames: function() {
			// summary: add id of widget to event names
			this.eventNames = {};
			for(var name in this.eventNamesDefault) {
				if (this.eventNames[name] === undefined) {
					this.eventNames[name] = this.id + "/" + this.eventNamesDefault[name];
				}
			}
		},

		initialize: function () {
			// summary: clear last selected item, when the list gets new content
			this._lastSelectedItem = undefined;
		},

		postCreate: function() {
			// summary: only add pagging events is pagging is activated
			this.inherited("postCreate", arguments);
			this.adjustEventNames();
			if(this.pagging){
				this.connect(this.PageDownNode, "onclick", 'pageDown');
				this.connect(this.PageUpNode, "onclick", 'pageUp');
			}

		},

		startup: function(){
			// summary: collect children that are inside the main dom node and put them inside array for later use
			this.children = this.getChildren();
			dojo.publish(this.eventNames.afterListCreate, [this]);
		},

		pageUp:function(){
			// summary: changes the visible elemnts by pagging one page down
			if(this._pagger.currentPage+1 != this._pagger.maxPage){
				var page = this._pagger.currentPage + 1;
				this._createVisibleChildren(this._allChildren,page);
			}
		},

		pageDown:function(){
			// summary: changes the visible elemnts by pagging one page up
			if(this._pagger.currentPage > 0){
				var page = this._pagger.currentPage - 1;
				this._createVisibleChildren(this._allChildren,page);
			}
		},

		pageTo: function(page){
			// summary: changes the visible elemnts by pagging to given page
			if(page >= 0 && page < this._pagger.maxPage){
				this._createVisibleChildren(this._allChildren,page);
			}
		},

		_setPagerButtons: function(startId, endId){
			// summary: creates pager buttons if needed and sets status of page up / down node
			dojo.removeClass(this.PaggerButtons,'HideElement');
			if(endId > this._allChildren.length){
				dojo.addClass(this.PageUpNode,'Disabled');
			}
			else{
				dojo.removeClass(this.PageUpNode,'Disabled');
			}
			if(startId == 0){
				dojo.addClass(this.PageDownNode,'Disabled');
			}
			else{
				dojo.removeClass(this.PageDownNode,'Disabled');
			}
			//create array of pages and fill them until current page is inside
			//remove first element if array is larger than 10 and current page are not inside
			//end if all pages are in or current page is at right position
			var pageIdArray = [];
			for(var i = 0; i < this._pagger.maxPage; i++){
				var pageId = i;
				pageIdArray.push(pageId);
				if(pageIdArray.length == 10){
					if($A(pageIdArray).exists(this._pagger.currentPage)){
						if($A(pageIdArray).find(this._pagger.currentPage) <= 5){
							break;
						}
						else{
							pageIdArray.shift();
						}
					}
					else{
						pageIdArray.shift();
					}
				}
			}
			//create spans for pager entrys, attach page events and highlight current page
			this.PageButtonsContainer.innerHTML = '';
			for( var j=0,jLength=pageIdArray.length ; j<jLength ; j++ ){
				currentPage = pageIdArray[j];
				//use PageButtonNode as prototype for page buttons
				var newPageButtonNode = this.PageButtonNode.cloneNode(true);
				this.PageButtonsContainer.appendChild(newPageButtonNode);
				this.connect(newPageButtonNode, 'onclick', epages.lang.hitch(this,this.pageTo, [currentPage]));
				if(currentPage == this._pagger.currentPage){
					dojo.addClass(newPageButtonNode,'Selected');
					newPageButtonNode.innerHTML = '<b> '+(currentPage+1)+' </b>';
				}
				else{
					newPageButtonNode.innerHTML = ' '+(currentPage+1)+' ';
				}
			}
		},

		_createVisibleChildren: function(elements,page){
			// summary: creates widgets for the current on this page of list visible children
			// creates all children if there is only one page
			//save Children and destroy old visible Children

			//remove old content
			this._allChildren = elements;
			this.destroyDescendants();
			this.initialize();
			//check pagger and display buttons if needed
			this._pagger.currentPage = page;
			if(this.pagging && this._pagger.maxPage > 1){
				var startId = page * this.paggingQuantity;
				var endId = startId + this.paggingQuantity;
				this._setPagerButtons(startId, endId);
			}
			else{
				var startId = 0;
				var endId = elements.length;
				dojo.addClass(this.PaggerButtons,'HideElement');
			}

			//createVisible Children
			for (var i = startId; i < endId; i++) {
				//could be possible that endId is greater than number of children
				if(i > this._allChildren.length){
					break;
				}
				var elm = this._allChildren[i];
				if(elm){
					elm.parentId = this.id;
					elm.store = this.store;
					var item = new (eval(this.widgetElementType))(elm);
					item.data = elm;
					this.addChild(item);
					item.startup();
					this._pagger.currentVisibleChildren.push(item);
				}
			}
			this.children = this.getChildren();
			dojo.publish(this.eventNames.afterSetChildren, [{ source: this, length: this.children.length }] );
		},

		setChildren: function(/*array*/ elements) {
			// summary: set children elements for list and show first page
			this._pagger.maxPage = Math.ceil(elements.length / this.paggingQuantity);
			this._createVisibleChildren(elements,0);
		},

		selectedNodes: function () {
			// summary: return current selected nodes of list can be more than one if multiSelect is enabled
			if (this.multiSelect != 'true') {
				if (this._lastSelectedItem === undefined){
					return []; // Array
				}
				return [this._lastSelectedItem]; // Array
			}
			// get selected widgets
			var nodes = dojo.filter(this.getChildren(), function (el) {
				return (typeof (el.isSelected) == 'boolean' && el.isSelected);
			});
			return nodes; // Array
		},

		selectedItems: function () {
			// summary: returns array of objectIds of current selected items
			var nodes = this.selectedNodes();
			var objectIds = dojo.map(nodes, function (el) {
				return el.objectId;
			});
			return objectIds; // Array
		},

		select: function(/*Elementlistitem*/ item) {
			if (this._lastSelectedItem !== undefined && this.multiSelect != 'true') {
				// deselect old selected item
				this._lastSelectedItem.deselect();
			}
			item.select();
			this._lastSelectedItem = item;
			// fire events
			dojo.publish(this.eventNames.select, [item]);
			if (this.onselect != ''){
				eval(this.onselect);
			}
		},

		deselect: function(/*Elementlistitem*/ item) {
			this._lastSelectedItem = undefined;
			item.deselect();
			// fire events
			dojo.publish(this.eventNames.deselect, [item]);
			if (this.ondeselect != ''){
				eval(this.ondeselect);
			}
		},

		deselectAll: function() {
			var items = this.selectedNodes();
			for( var i=0,iLength=items.length ; i<iLength ; i++ ) {
				var item = items[i];
				this.deselect(item);
			}
		},

		_childById: function (objectId) {
			for( var i=0,iLength=this.children.length ; i<iLength ; i++ ) {
				if (this.children[i].objectId == objectId){
					return this.children[i];
				}
			}
			return;
		},

		doSelectItem: function(/*Elementlistitem*/item, /*boolean?*/isSelected, evt) {
			// cannot select item if it's disabled
			if(item.disabled) {
				return;
			}

			if (typeof(item) == 'string' || typeof(item) == 'number') {
				item = this._childById(item);
			}
			var type = this.selectTypes.SINGLE;
			if (this.multiSelect == 'true' && evt != undefined) {
				if (evt.ctrlKey) {
					type = this.selectTypes.ADD;
				} else if (evt.shiftKey) {
					type = this.selectTypes.LIST;
				}
			}
			switch (type) {
				case this.selectTypes.LIST:
					var select = false;
					var lastSelectedItem = this._lastSelectedItem;
					// use first selected item in list, if exists
					if (lastSelectedItem == undefined && this.selectedNodes().length > 0) {
						lastSelectedItem = (this.selectedNodes())[0];
					}
					for( var i=0,iLength=this.children.length ; i<iLength ; i++ ) {
						var child = this.children[i];
						if (!select &&
								(child.objectId == item.objectId ||
								 (lastSelectedItem == undefined || child.objectId == lastSelectedItem.objectId))) {
							select = true;
						}
						else if (select &&
										 (child.objectId == item.objectId ||
											(lastSelectedItem != undefined && child.objectId == lastSelectedItem.objectId))) {
							this.select(child);
							break;
						}
						if (select){
							this.select(child);
						}
					}
					break;
				case this.selectTypes.ADD:
					if (isSelected) {
						this.deselect(item);
					} else {
						this.select(item);
					}
					break;
				default:
				case this.selectTypes.SINGLE:
					this.deselectAll();
					this.select(item);
					break;
			}
			// set focus to avoid text selection
			this.domNode.focus();
		},

		getItemByIdentity : function(/* String */identifierName, identity) {
			for(var el in this.children) {
				if(this.children[el][identifierName] == identity){
					return this.children[el];
				}
			}
		}
	}
);