/*
 * Copyright 2005 - 2009  Zarafa B.V.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3, 
 * as published by the Free Software Foundation with the following additional 
 * term according to sec. 7:
 *  
 * According to sec. 7 of the GNU Affero General Public License, version
 * 3, the terms of the AGPL are supplemented with the following terms:
 * 
 * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of
 * the Program under the AGPL does not imply a trademark license.
 * Therefore any rights, title and interest in our trademarks remain
 * entirely with us.
 * 
 * However, if you propagate an unmodified version of the Program you are
 * allowed to use the term "Zarafa" to indicate that you distribute the
 * Program. Furthermore you may use our trademarks where it is necessary
 * to indicate the intended purpose of a product or service provided you
 * use it in accordance with honest practices in industrial or commercial
 * matters.  If you want to propagate modified versions of the Program
 * under the name "Zarafa" or "Zarafa Server", you may only do so if you
 * have a written permission by Zarafa B.V. (to acquire a permission
 * please contact Zarafa at trademark@zarafa.com).
 * 
 * The interactive user interface of the software displays an attribution
 * notice containing the term "Zarafa" and/or the logo of Zarafa.
 * Interactive user interfaces of unmodified and modified versions must
 * display Appropriate Legal Notices according to sec. 5 of the GNU
 * Affero General Public License, version 3, when you propagate
 * unmodified or modified versions of the Program. In accordance with
 * sec. 7 b) of the GNU Affero General Public License, version 3, these
 * Appropriate Legal Notices must retain the logo of Zarafa or display
 * the words "Initial Development by Zarafa" if the display of the logo
 * is not reasonably feasible for technical reasons."
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *  
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

/**
 * ListModule
 * The list module extends from Module 
 */
ListModule.prototype = new Module;
ListModule.prototype.constructor = ListModule;
ListModule.superclass = Module.prototype;

function ListModule(id, element, title, data)
{
	if(arguments.length > 0) {
		this.init(id, element, title, data);
	}
}

/**
 * Function which intializes the module.
 * @param integer id id
 * @param object element the element for the module
 * @param string title the title of the module
 * @param object data the data (storeid, entryid, ...)  
 */ 
ListModule.prototype.init = function(id, element, title, data, uniqueid)
{
	ListModule.superclass.init.call(this, id, element, title);

	this.dblclick = false;
	
	// Storeid
	this.storeid = false;
	
	// Folder Entryid
	this.entryid = false;
	
	// List of entryids in table
	this.entryids = new Object();
	
	// Properties which are shown in the table view as columns.
	this.propertylist = new Array();
	this.properties = new Array();
	
	// Contains all the properties for every item in this module (keys are the entryids/uniqueids)
	this.itemProps = new Object();
	
	// Sort array
	this.sort = false;
	
	// Columns which should be added or deleted in the next request
	this.columns = false;

	//entry id for changing importance of item
	this.messageID = false;	
	
	//contains unixtimestamp of dates...
	this.unixtime = new Object();
	
	// Previous value of item is stored in this variable
	this.previousvalue = new Array();
	
	// Previously selected message
	this.prevselectedMessage = false;
	this.prevselMessage = false;
	
	// Message which is in the editable form
	this.editMessage = false;
	
	//stopbubble
	this.stopbubble = false;
	
	// Table
	// Start row in the table
	this.rowstart = 0;
	
	// Rowcount, which holds the number of rows queried (25, 50, ...)
	this.rowcount = 0;
	
	// Total number of rows in the folder
	this.totalrowcount = 0;
	
	// Selected messages in the table, which will be used for delete, copy or open.
	this.selectedMessages = new Array();
	
	// This is the first selected message in a range; ie it is reset when you single-select a message
	this.selectedFirstMessage = 0;
	
	// Select contextmenu message
	this.selectedContextMessage = false;
	
	// Unique ID for this module (a column id that uniquely identifies a row)
	if(!uniqueid)
		this.uniqueid = "entryid";
	else
		this.uniqueid = uniqueid;
	
	// View Object
	this.viewController = new ViewController();

	if (!data || !data["has_no_menu"]) {
		webclient.menu.reset();
		this.menuItems = new Array();
		this.menuItems.push(webclient.menu.createMenuItem("delete", false, _("Delete messages"), eventListDeleteMessages));
		this.menuItems.push(webclient.menu.createMenuItem("copy", false, _("Copy/Move messages"), eventListCopyMessages));
		this.menuItems.push(webclient.menu.createMenuItem("print", false, _("Print"), eventListPrintMessage));
		this.menuItems.push(webclient.menu.createMenuItem("addressbook", false, _("Addressbook"), eventListShowAddressbook));
	}
	
	var items = new Array();
	items.push(webclient.menu.createMenuItem("open", _("Open"), false, eventListContextMenuOpenMessage));
	items.push(webclient.menu.createMenuItem("print", _("Print"), false, eventListContextMenuPrintMessage));
	items.push(webclient.menu.createMenuItem("seperator", ""));
	items.push(webclient.menu.createMenuItem("categories", _("Categories"), false, eventListContextMenuCategoriesMessage));
	items.push(webclient.menu.createMenuItem("seperator", ""));
	items.push(webclient.menu.createMenuItem("delete", _("Delete"), false, eventListContextMenuDeleteMessage));
	//items.push(webclient.menu.createMenuItem("copy", _("Copy/Move Message"), false, eventListContextMenuCopyMessage));
	this.contextmenu = items;

	// Tooltip messages
	this.tooltip = new Array();
	this.tooltip["importance"] = new Array();
	this.tooltip["importance"]["value"] = new Array();
	this.tooltip["importance"]["value"][0] = _("Low");
	this.tooltip["importance"]["value"][1] = _("Normal");
	this.tooltip["importance"]["value"][2] = _("High");
	this.tooltip["importance"]["css"] = new Array();
	this.tooltip["importance"]["css"][0] = "icon_importance_low";
	this.tooltip["importance"]["css"][1] = "icon_taskarrow";
	this.tooltip["importance"]["css"][2] = "icon_importance_high";
	
	// Events which set in the table
	this.events = new Object();
	this.events["column"] = new Object();
	this.events["column"]["click"] = eventListColumnSort;
	this.events["column"]["contextmenu"] = eventListColumnContextMenu;

	this.events["menu"] = new Object();
	this.events["menu"]["importance"] = new Object();
	this.events["menu"]["importance"]["mouseover"] = eventMenuImportanceMouseOver;
	this.events["menu"]["importance"]["click"] = eventMenuImportanceClick;
	this.events["menu"]["importance"]["mousedown"] = eventListStopBubble;
	this.events["menu"]["importance"]["mouseout"]  = eventMenuImportanceMouseOut;
	
	this.events["insertrow"] = new Object();
	this.events["insertrow"]["click"] = eventInputFieldClick;
	this.events["insertrow"]["mousedown"] = eventDeselectMessages;
	this.events["insertrow"]["keydown"]= eventClickSaveMessage;
	this.events["insertrow"]["mousemove"]= eventListInsertRowMouseMove;
	this.events["insertrow"]["selectstart"]= eventListInsertRowMouseMove;
	
	this.events["insertcolumn"] = new Object();
	this.events["insertcolumn"]["importance"] = new Object();
	this.events["insertcolumn"]["importance"]["mousedown"] = eventClickChangeImportance;

	this.events["row"] = new Object();
	this.events["row"]["mousedown"] = eventListMouseDownMessage;
	this.events["row"]["mouseup"] = eventListMouseUpMessage;
	this.events["row"]["dblclick"] = eventListDblClickMessage;
	this.events["row"]["contextmenu"] = eventListContextMenuMessage;
	this.events["row"]["mousemove"]= eventListRowMouseMove;
	this.events["row"]["selectstart"]= eventListRowMouseMove;
	
	this.events["rowcolumn"] = new Object();
	this.events["rowcolumn"]["icon_index"] = new Object();
	this.events["rowcolumn"]["icon_index"]["click"] = eventListChangeReadFlag;
	this.events["rowcolumn"]["flag_icon"] = new Object();
	this.events["rowcolumn"]["flag_icon"]["mouseover"] = eventListMouseOverFlag;
	this.events["rowcolumn"]["flag_icon"]["mouseout"] = eventListMouseOutFlag;
	this.events["rowcolumn"]["flag_icon"]["click"] = eventListChangeFlagStatus;
	this.events["rowcolumn"]["complete"] = new Object();
	this.events["rowcolumn"]["complete"]["click"] = eventListChangeCompleteStatus;
	this.events["rowcolumn"]["complete"]["mouseup"] = eventListStopBubble;
	this.events["rowcolumn"]["complete"]["mousedown"] = eventListStopBubble;
	this.events["rowcolumn"]["importance"] = new Object();
	this.events["rowcolumn"]["importance"]["mouseup"] = eventClickChangeImportance;
	this.events["rowcolumn"]["importance"]["mousedown"] = eventListStopBubble;
	
	dhtml.addEvent(this.id, document.body, "mouseup", eventListCheckSelectedContextMessage);
	
	// Set onDrop Event
	if(typeof(dragdrop) != "undefined") {
		dragdrop.setOnDropGroup("folder", this.id, eventListDragDropTarget);
	}
	
	this.addEventHandler("openitem", this, this.onOpenItem);

	this.setData(data);
	
	// Enable these features by default
	this.enableSorting = true;
	this.enableVariableColumns = true;
}

/**
 * Function which intializes the view.
 */ 
ListModule.prototype.initializeView = function()
{
	if (this.title!=false){
		this.setTitle(this.title, false, true);
	}
	this.contentElement = dhtml.addElement(this.element, "div");

	this.viewController.initView(this.id, "table", this.contentElement, this.events, null, this.uniqueid);
}

/**
 * Function which resizes the view.
 */ 
ListModule.prototype.resize = function()
{
	this.contentElement.style.height = (this.element.offsetHeight - this.contentElement.offsetTop - 5) + "px";
	this.viewController.resizeView();
}

/**
 * Function which execute an action. This function is called by the XMLRequest object.
 * @param string type the action type
 * @param object action the action tag 
 */ 
ListModule.prototype.execute = function(type, action)
{
	webclient.menu.showMenu();
	
	switch(type)
	{
		case "list":
			this.messageList(action);
			break;
		case "item":
			this.item(action);
			break;
		case "delete":
			this.deleteItems(action);
			break;
		case "swap":
			this.swapItems(action);
			break;
		case "failed":
			this.handleActionFailure(action);
			break;
	}
}

/**
 * Report the failure of an action
 */
ListModule.prototype.handleActionFailure = function(action)
{
	switch(dhtml.getXMLValue(action, "action_type", "none")){
		case "delete":
		case "copy":
		case "move":
			alert(_("The operation is completed, but not all items could be copied, deleted or moved."));
			break;
	}
}

/**
 * Swaps two rows, the entryids are in the XML action
 */
ListModule.prototype.swapItems = function(action)
{
	var entryids = action.getElementsByTagName(this.uniqueid);
	if(entryids.length != 2)
		return;

	var entryid1 = dhtml.getXMLNode(action, this.uniqueid, 0).firstChild.nodeValue;		
	var entryid2 = dhtml.getXMLNode(action, this.uniqueid, 1).firstChild.nodeValue;

	var rowid1 = this.getRowId(entryid1);
	var rowid2 = this.getRowId(entryid2);
	
	var elem1 = dhtml.getElementById(rowid1);
	var elem2 = dhtml.getElementById(rowid2);
	
	var parent = elem1.parentNode;

	// InsertBefore doesn't only insert, it also removes the element from
	// the old position. So this is a swap	
	parent.insertBefore(elem1, elem2);
}

/**
 * Function which takes care of the list action. It is responsible for
 * calling the "addItems" function in the view.
 * @param object action the action tag
 */ 
ListModule.prototype.messageList = function(action)
{
	this.propertylist = new Array();
	this.properties = new Array();

	//properties for insert column
	this.inputproperties = new Array();

	var properties = action.getElementsByTagName("column");

	// Columns
	for (var i = 0; i < properties.length; i++)
	{
		var id = properties[i].getElementsByTagName("id")[0];
		
		if(id && id.firstChild) {
			var order = properties[i].getElementsByTagName("order")[0];
			var name = properties[i].getElementsByTagName("name")[0];
			var title = properties[i].getElementsByTagName("title")[0];
			var length = properties[i].getElementsByTagName("length")[0];
			var visible = properties[i].getElementsByTagName("visible")[0];
			var type = properties[i].getElementsByTagName("type")[0];
			
			var property = new Object();
			property["id"] = id.firstChild.nodeValue;
			property["order"] = (order && order.firstChild?order.firstChild.nodeValue:false);
			property["name"] = (name && name.firstChild?name.firstChild.nodeValue:false);
			property["title"] = (title && title.firstChild?title.firstChild.nodeValue:false);
			property["length"] = (length && length.firstChild?length.firstChild.nodeValue:false);
			property["visible"] = (visible && visible.firstChild?visible.firstChild.nodeValue:false);
			property["type"] = (type && type.firstChild?type.firstChild.nodeValue:false);
			
			if(webclient.hasRightPane){
				switch(property["id"]){
					case ("display_to"):
					case ("sent_representing_name"):
					case ("client_submit_time"):
					case ("message_delivery_time"):
						this.propertylist.push(property);
						if(property["visible"]) {
							this.properties.push(property);
						}
						break;
				}
			}else{
				this.propertylist.push(property);
				if(property["visible"]) {
					this.properties.push(property);
				}
			}
		}
	}

	var inputProp = action.getElementsByTagName("insertcolumn");

	for(var i = 0; i < inputProp.length; i++)
	{
		var id = inputProp[i].getElementsByTagName("id")[0];

		if (id && id.firstChild) {			
			var name = inputProp[i].getElementsByTagName("name")[0];
			var order = inputProp[i].getElementsByTagName("order")[0];
			var visible = inputProp[i].getElementsByTagName("visible")[0];
			var type = inputProp[i].getElementsByTagName("type")[0];
			var length = inputProp[i].getElementsByTagName("length")[0];
			var title = inputProp[i].getElementsByTagName("title")[0];
			var readonly = inputProp[i].getElementsByTagName("readonly")[0];

			
			var inputproperty = new Object();
			inputproperty["id"] = id.firstChild.nodeValue;
			inputproperty["order"] = (order && order.firstChild?order.firstChild.nodeValue:false);
			inputproperty["name"] = (name &&  name.firstChild? name.firstChild.nodeValue:false);
			inputproperty["visible"] = ( visible &&  visible.firstChild? visible.firstChild.nodeValue:false);
			inputproperty["length"] = (length && length.firstChild?length.firstChild.nodeValue:false);
			inputproperty["type"] = (type && type.firstChild?type.firstChild.nodeValue:false);
			inputproperty["title"] = (title && title.firstChild?title.firstChild.nodeValue:false);
			inputproperty["readonly"] = (readonly && readonly.firstChild?readonly.firstChild.nodeValue:false);
		
			//set order of input columns according to header columns (field chooser)
			for (var j=0;j<this.properties.length;j++) {
				if (this.properties[j]["id"] == inputproperty["name"] ) {
					inputproperty["order"] = this.properties[j]["order"];
					this.inputproperties.push(inputproperty);
				}
			}
		}
	}

	//Sort
	var sort = action.getElementsByTagName("sort")[0];
	if(sort && sort.firstChild) {
		var sortColumn = sort.firstChild.nodeValue;
		var sortDirection = sort.getAttribute("direction");
		
		var column = new Object();
		column["attributes"] = new Object();
		column["attributes"]["direction"] = sortDirection;
		column["_content"] = sortColumn;
		this.sort = new Array(column);
	}

	this.viewController.deleteLoadMessage();
	this.entryids = this.viewController.addItems(action.getElementsByTagName("item"), this.properties, action, false, this.inputproperties);
	
	//Show full GAB is enabled/disabled
	var disable_gab = action.getElementsByTagName("disable_full_gab")[0];
	if (disable_gab) {
		var disable_gab_value = dhtml.getTextNode(disable_gab.getElementsByTagName("value")[0], 0);
		this.viewController.GAB(disable_gab_value);
	}
	
	// remember item properties
	this.itemProps = new Object();
	var items = action.getElementsByTagName("item");
	for(var i=0;i<items.length;i++){
		this.updateItemProps(items[i]);
	}

	if(typeof(ComboBox) != "undefined") {
		this.paging(action);
	}

	if(this.executeOnLoad) {
		this.executeOnLoad();
	}
	
	//As bubbling of 'mousedown' event from row to divelement in LISTVIEW is prevented, initially focus is given to divelement.
	if (dhtml.getElementById("divelement")){
		dhtml.executeEvent(dhtml.getElementById("divelement"),"mousedown");
	}
	
	//Call the function to select the old selected items if there is any, after reloading the mail list with new mails.
	if(typeof moduleObject != "undefined" && moduleObject.oldSelectedMailEntryId){
		this.selectOldSelectedEmail();
	}
}

/**
 * Function which takes care of the paging element, above the table view.
 * @param object action the action tag 
 */ 
ListModule.prototype.paging = function(action, noReload)
{
	if(action) {
		var page = action.getElementsByTagName("page")[0];
		
		if(page) {
			var rowstart = page.getElementsByTagName("start")[0];
			if(rowstart && rowstart.firstChild) {
				this.rowstart = rowstart.firstChild.nodeValue * 1;
			}
			
			var rowcount = page.getElementsByTagName("rowcount")[0];
			if(rowcount && rowcount.firstChild) {
				this.rowcount = rowcount.firstChild.nodeValue * 1;
			}
			
			var totalrowcount = page.getElementsByTagName("totalrowcount")[0];
			if(totalrowcount && totalrowcount.firstChild) {
				this.totalrowcount = totalrowcount.firstChild.nodeValue * 1;
			}
			
			if(this.totalrowcount > this.rowcount) {
				var selected = this.viewController.pagingElement(this.totalrowcount, this.rowcount, this.rowstart);

				if(!selected && !noReload) {
					this.rowstart -= this.rowcount;
					this.list();
				}
			} else {
				this.viewController.removePagingElement();
				if(this.rowstart > 0 && !noReload) {
					this.rowstart = 0;
					this.list();
				}
			}
		}
	}
}

/**
 * Function which selects the first item in the view.
 */ 
ListModule.prototype.selectFirstItem = function()
{
	var element = dhtml.getElementById("0");

	if(element) {
		eventListMouseDownMessage(this, element, false);
		eventListMouseUpMessage(this, element, false);
	}
}

/**
 * Function which adds or updates an item in the view.
 * @param object action the action tag 
 */ 
ListModule.prototype.item = function(action)
{
	var items = action.getElementsByTagName("item");
	this.editMessage = false;
	// Loop through all updated items (add/modify)
	if(items && items.length > 0) {
		for(var i = 0; i < items.length; i++)
		{
			var item = items[i];
			var entryid = dhtml.getXMLValue(item, this.uniqueid);
			var parent_entryid = dhtml.getXMLValue(item, "parent_entryid", false); 
			
			// When parent_entryid exists, it must be the same as the entryid of this listmodule, else we ignore this item.
			// It is only possible to get here with an invalid parent_entryid when we are using the search, you know this by 
			// the 'searchfolder' attribute on the action element.
			if(!parent_entryid || (parent_entryid==this.entryid && entryid) || action.getAttribute("searchfolder")) {
				// Get the DOM element ID for this object
				var rowid = this.getRowId(entryid);
				var element = dhtml.getElementById(rowid);

				// If it exists, it's an update
				if(element && !item.getAttribute("instance")) {
					var entry = this.viewController.updateItem(element, item, this.properties);
					
					if(entry) {
						// Remember this element id -> entry id mapping of this object
						this.entryids[rowid] = undefined;
						this.entryids[entry["id"]] = entry[this.uniqueid];
					} else {
						// If the view doesn't support an update, post a refresh
						this.list();
						
						// Since we're reloading, we might as well stop what we're doing ...
						return;
					}
				}
				else {
					// Otherwise it's a new item
					var entry = this.viewController.addItem(item, this.properties, action);
					
					if(entry) {
						// Remember this element id -> entry id mapping of this object
						this.entryids[entry["id"]] = entry[this.uniqueid];
					} else {
						// If the view doesn't support an add, post a refresh
						this.list();
						
						// Reload, might as well stop processing
						return;
					}
				}
			}

			// update property data of items
			this.updateItemProps(item);
		}
	}
	
	//As bubbling of 'mousedown' event from row to divelement in LISTVIEW is prevented, initially focus is given to divelement.
	if (dhtml.getElementById("divelement")){
		dhtml.executeEvent(dhtml.getElementById("divelement"),"mousedown");
	}
}

/**
 * Function which deletes one or more items in the view.
 * @param object action the action tag 
 * @TODO: move this to the view
 */ 
ListModule.prototype.deleteItems = function(action)
{
	var entryid = action.getElementsByTagName(this.uniqueid);
	this.totalrowcount -= entryid.length;

	// check if one of the messages were selected
	var isSelected = false;
	// array which stores all rowids which are to be deleted.
	var selectedrowids = new Array();
	for(var i = 0; i<entryid.length; i++){
		var rowid = this.getRowId(entryid[i].firstChild.nodeValue);
		selectedrowids.push(rowid);
		if (this.isMessageSelected(rowid)){
			isSelected = true;
		}
	}
	
	// Select next (or if not exists the previous) message when that message is selected)
	if (isSelected){
		var first_entryid = entryid[entryid.length - 1];
		if(first_entryid && first_entryid.firstChild ) {
			var rowid = this.getRowId(first_entryid.firstChild.nodeValue);
			var item = dhtml.getElementById(rowid);

			if(item) {
				var nextItem = item.nextSibling;
				if(nextItem) {
					// find next item untill we get an unselected item
					while(inArray(nextItem.id, selectedrowids) === true) {
						if(nextItem.nextSibling) {
							nextItem = nextItem.nextSibling;
							continue;
						} else {
							// this is the last item, so no next item left
							nextItem = null;
							break;
						}
					}
				}

				// If there isnt any next item which is unselected then go for previous items
				if(!nextItem) {
					nextItem = item.previousSibling;
					if(nextItem) {
						while(inArray(nextItem.id, selectedrowids) === true) {
							if(nextItem.previousSibling) {
								nextItem = nextItem.previousSibling;
								continue;
							} else {
								// probably the whole view is empty or all items are selected
								nextItem = null;
								break;
							}
						}
					}
				}

				if(nextItem) {
					dhtml.executeEvent(nextItem, "mousedown");
					dhtml.executeEvent(nextItem, "mouseup");
        		} else {
    	    	    // No more items, select nothing
	    	        this.selectedMessages = new Array();
                }
            }
		}
	}
	
	// Remove elements from the view
	for(var i = 0; i < entryid.length; i++)
	{
		if(entryid[i] && entryid[i].firstChild) {
			var entryiditem = entryid[i].firstChild.nodeValue;

			var rowid = this.getRowId(entryiditem);
			
			this.sendEvent("deleteitem", entryiditem);
				
			while(rowid) {
				var item = dhtml.getElementById(rowid);
				
				if(item) {
					dhtml.deleteElement(item);
				}
				
				// Remove item properties
				this.deleteItemProps(entryiditem);

				// Also remove the mapping in the element id -> entryid mapping
				this.entryids[rowid] = null;
				rowid = this.getRowId(entryiditem);
			}
		}
	}
	
	this.actionAfterDelete(action);
}

/**
 * Function which executes a set of action after some items are deleted
 */ 
ListModule.prototype.actionAfterDelete = function(action)
{
	// Update paging
	if(typeof moduleObject != "undefined") {
		var combobox = moduleObject.viewController.viewObject.combobox;
	}
	if(combobox) {
		var pageElement = dhtml.getElementsByClassName("page")[0];
		var comboboxElement = dhtml.getElementById("pagecombobox");
		
		dhtml.deleteAllChildren(comboboxElement);
		pageElement.style.display = "none";
		
		combobox.destructor();

		this.paging(action);
	}

	// fix cursor
	var curPos = this.viewController.getRowNumber(this.viewController.getCursorPosition());
	var rowCount = this.viewController.getRowCount();
	if (curPos > rowCount || (curPos==0 && rowCount>0)){
		curPos = rowCount -1; // select last item;
	}
	
	this.viewController.setCursorPosition(this.viewController.getElemIdByRowNumber(curPos));
	
	// empty the right pane after checking that list is empty or not.
	if(this.previewreadmailitemmodule) {
		dhtml.deleteAllChildren(this.previewreadmailitemmodule.element);
	}
}

/**
 * Function which sets the data for this module (storeid, entryid, ...).
 * @param object data data
 */ 
ListModule.prototype.setData = function(data)
{
	if(data) {
		for(var property in data)
		{
			this[property] = data[property];
		}
	}
}

/**
 * Function which returns the corresponding rowid for an entryid.
 * @param string entryid entryid
 * @return int row id  
 */ 
ListModule.prototype.getRowId = function(entryid)
{
	var rowid = false;
	
	for(var i in this.entryids)
	{
		if(this.entryids[i] == entryid) {
			rowid = i;
		}
	}
	
	return rowid;
}

/**
 * Function which sends a request to the server, with the action "list".
 * @param boolean useTimeOut use a time out for the request 
 */ 
ListModule.prototype.list = function(useTimeOut, noLoader)
{
    var data = new Object();
    data["store"] = this.storeid;
    data["entryid"] = this.entryid;

    this.sort = this.loadSortSettings();
    if(this.sort) {
        data["sort"] = new Object();
        data["sort"]["column"] = this.sort;
    }
    
    this.columns = this.loadFieldSettings();
    
    if(this.columns) {
        var tablecolumns = new Array();
        for(var i = 0; i < this.columns.length; i++)
        {
            var column = new Object();
            column["attributes"] = new Object();
            column["attributes"]["action"] = this.columns[i]["action"];
            
            if(this.columns[i]["order"] !== false) {
                column["attributes"]["order"] = this.columns[i]["order"];
            }
            
            column["_content"] = this.columns[i]["id"];
            tablecolumns.push(column);	
        }
        
        data["columns"] = new Object();
        data["columns"]["column"] = tablecolumns;
        
        this.columns = new Array();
    }
    
    
    data["restriction"] = new Object();
    
    if(this.getRestrictionData) {
        data["restriction"] = this.getRestrictionData(); 
        if(data["restriction"] == false)
            return; // Abort list if module requires restriction but has none
    }
    
    data["restriction"]["start"] = this.rowstart;

	if(typeof this.searchSubfolders != "undefined") {
		// if search folder then also check for subfolders option
		data["subfolders"] = this.searchSubfolders;
	}

	// Retrieve data in extended (address cards view, calendar view, etc...) way 
	// or the normal (table) way.
	data["data_retrieval"] = (this.viewController.view=="table"?"normal":"extended");

    webclient.xmlrequest.addData(this, "list", data);
    
    if (!noLoader)
        this.viewController.loadMessage();
}

/**
 * Function which saves a set of properties for a message.
 * @param object props the properties which should be saved 
 */ 
ListModule.prototype.save = function(props, send, drag)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["props"] = props;
	//if an  recurring appointment item is drag to some other position then true.
	if(drag){
		data["drag"] = true;
	}

	if (send){
		data["send"] = true;
	}

	webclient.xmlrequest.addData(this, "save", data);
}

/**
 * Function which sets the PR_MESSAGE_FLAGS (read/unread).
 * @param string messageEntryid the entryid of the message
 * @param string flag the flags comma seperated list of flags "read","receipt","noreceipt" or "unread"
 */ 
ListModule.prototype.setReadFlag = function(messageEntryid, flag)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["entryid"] = messageEntryid;
	
	if(flag) {
		data["flag"] = flag;
	}
	
	webclient.xmlrequest.addData(this, "read_flag", data);
}

ListModule.prototype.sendReadReceipt = function(entryID)
{
	var result = false;
	if (entryID){
		var message_flags = this.itemProps[entryID]["message_flags"]
		if (message_flags!=null && (message_flags & MSGFLAG_RN_PENDING) == MSGFLAG_RN_PENDING){
			switch(webclient.settings.get("global/readreceipt_handling", "ask")){
				case "ask":
					result = confirm(_("The sender of this message has asked to be notified when you read this message.")+"\n"+_("Do you wish to notify the sender?"));
					break;
				case "never":
					result = false;
					break;
				case "always":
					result = true;
					break;
			}
		}
	}
	return result;
}

/**
 * Function which deletes a list of selected messages
 */ 
ListModule.prototype.deleteMessages = function(messages)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;

	var folder = webclient.hierarchy.getFolder(this.entryid);
	
	if(folder && (folder.rights["deleteowned"] > 0 || folder.rights["deleteany"] > 0)){

		if (webclient.hierarchy.isSpecialFolder("wastebasket", this.entryid)){
			if (!confirm(_("Are you sure that you want to permanently delete the selected item(s)?"))){
				return;
			}
		}
		
		data["entryid"] = new Array();
		if(messages.length > 0) {
			for(var i = 0; i < messages.length; i++) {
				// check row is not selected for editing...
				if (this.editMessage !== this.selectedMessages[i]){
					data["entryid"].push(this.entryids[messages[i]]);
				}
			}
		}

		data["start"] = this.rowstart;
		data["rowcount"] = this.rowcount;

		if(this.sort) {
			data["sort"] = new Object();
			data["sort"]["column"] = this.sort;
		}

		if(data["entryid"].length > 0) {
			// don't send request if entryid is empty
			webclient.xmlrequest.addData(this, "delete", data);
		}
	}
}

/**
 * Function which deletes one message.
 * @param string messageEntryid entryid of the message 
 */ 
ListModule.prototype.deleteMessage = function(messageEntryid, elementid)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["entryid"] = messageEntryid;

	var folder = webclient.hierarchy.getFolder(this.entryid);

	// FIXME: better checking for rights needed
	if(folder && (folder.rights["deleteany"] > 0 || folder.rights["deleteowned"] > 0)){
		webclient.xmlrequest.addData(this, "delete", data);
	}
}

/**
 * Function which copies or moves messages.
 * @param string destinationFolder entryid of destination folder
 * @param string type "copy" or "move"
 * @param boolean dragdrop true - action is after drag drop event (optional)
 * @param string messageEntryid the drag/dropped message entryid
 * @param string destStore the drag/dropped message entryid
 */ 
ListModule.prototype.copyMessages = function(destStore, destinationFolder, type, dragdrop, messageEntryid)
{
	messageEntryids = new Array();
	if(typeof messageEntryid != "object"){
		messageEntryids[0] = messageEntryid;
	}else{
		messageEntryids = messageEntryid;
	}

	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["destinationfolder"] = destinationFolder;
	data["destinationstore"] = destStore;
	if(!destStore){
		data["destinationstore"] = this.storeid;
	}

	data["entryid"] = new Array();

	if(type == "move") {
		data["movemessages"] = "1";	
	} 
	
	if(typeof messageEntryid == "object"){
		data["entryid"] = messageEntryid;
		webclient.xmlrequest.addData(this, "copy", data);
	}else{
		for(var j=0;j<messageEntryids.length;j++){
			messageEntryid = messageEntryids[j];

			var messages = this.getSelectedMessages(messageEntryid);

			if(!dragdrop) {
				for(var i in messages) {
					data["entryid"].push(this.entryids[messages[i]]);
				}
			} else {
				if(typeof messageEntryid != "undefined" && messageEntryid) {
					data["entryid"].push(messageEntryid);
				}
			}
			
			if(data["entryid"].length > 0) {
				// don't send request if entryid is empty
				webclient.xmlrequest.addData(this, "copy", data);
			}
		}
	}

	if(type == "copy" && this.entryid == destinationFolder) {
		this.list(true);
	}
}

ListModule.prototype.showCopyMessagesDialog = function()
{
	if(typeof this.selectedMessages != "undefined" && this.selectedMessages.length > 0) {
		webclient.openModalDialog(this, "copymessages", DIALOG_URL+"task=copymessages_modal&storeid="+this.storeid, 300, 300);
	} else {
		alert(_("Please select a message to copy/move."));
	}
}

/**
 * Function which set the FLAG.
 * @param string messageEntryid the entryid of the message
 * @parm integer flagStatus the flag status
 * @param integer flagIcon the icon of the flag   
 */ 
ListModule.prototype.flagStatus = function(messageEntryid, flagStatus, flagIcon)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["props"] = new Object();
	data["props"]["entryid"] = messageEntryid;
	data["props"]["flag_status"] = flagStatus;
	data["props"]["flag_icon"] = flagIcon;
	data["props"]["flag_request"] = _("Red");
	data["props"]["reply_requested"] = true;
	data["props"]["response_requested"] = true;
	data["props"]["flag_complete_time"] = "";

	if (flagStatus == 1){ // completed
		data["props"]["reminder_set"] = "false";
		data["props"]["reply_requested"] = "false";
		data["props"]["response_requested"] = "false";
		data["props"]["flag_complete_time"] = parseInt((new Date()).getTime()/1000);
	}
	
	if (flagStatus == 0 && flagIcon == 0){
		data["props"]["reminder_set"] = "false";
		data["props"]["reply_requested"] = "false";
		data["props"]["response_requested"] = "false";
		data["props"]["flag_request"] = "";
	}

	webclient.xmlrequest.addData(this, "save", data);
}

/**
 * Function which is used for setting a message complete (task)
 * @param string messageEntryid entryid of the message
 * @param boolean complete true - set message complete  
 */ 
ListModule.prototype.completeStatus = function(messageEntryid, complete)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["props"] = new Object();
	data["props"]["entryid"] = messageEntryid;
	data["props"]["complete"] = (complete?"1":"-1");
	data["props"]["status"] = (complete?2:0);
	data["props"]["percent_complete"] = (complete?1:0);
	
	webclient.xmlrequest.addData(this, "save", data);
}

/**
 * Function which set the categories on a message
 * @param string messageEntryid entryid of the message
 * @param string categories list of categories to be set, divided by ; (semi-colon)  
 */ 
ListModule.prototype.setCategories = function(messageEntryid, categories)
{
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["props"] = new Object();
	data["props"]["entryid"] = messageEntryid;
	data["props"]["categories"] = categories;

	webclient.xmlrequest.addData(this, "save", data);
}

/**
 * Destructor
 */ 
ListModule.prototype.destructor = function(moduleObject)
{
	dhtml.removeEvent(document.body, "mouseup", eventListCheckSelectedContextMessage);

	if(moduleObject){
		moduleObject.element.innerHTML = "";
		moduleObject.viewController.destructor();
	}
}

/**
* Function to change the current page (when more then one pages exists)
*
*@param int page The page number to switch to.
*/
ListModule.prototype.changePage = function(page)
{
	this.rowstart = page * this.rowcount;
	this.list();
}

/**
* Function to open a print dialog
*
*@param string entryid The entryid for the item
*/
ListModule.prototype.printItem = function(entryid)
{
	// please note that this url is also printed, so make it more "interesting" by first set the entryid
	webclient.openModalDialog(this, "printing", DIALOG_URL+"entryid="+entryid+"&storeid="+this.storeid+"&task=printitem_modal", 600, 600);
}

ListModule.prototype.saveFieldSettings = function(data)
{
	var path = "folders/entryid_"+this.entryid+"/fields";
	var sendData = Object();
	for(var i=0;i<data.length;i++){
		var item = new Object();
		if(data[i]["order"]){
			item["order"] = data[i]["order"];
		}
		item["action"] = data[i]["action"];
		item["id"] = data[i]["id"];
		sendData[data[i]["id"]] = item;
	}
	webclient.settings.deleteSetting(path);
	webclient.settings.setArray(path,sendData);
}

ListModule.prototype.loadFieldSettings = function()
{
	var path = "folders/entryid_"+this.entryid+"/fields";
	data = webclient.settings.get(path);
	var result = new Array();
	for(var i in data){
		result.push(data[i]);
	}
	return result;
}

ListModule.prototype.saveSortSettings = function (data)
{
	var path = "folders/entryid_"+this.entryid+"/sort";
	webclient.settings.deleteSetting(path);
	webclient.settings.setArray(path,data);
}

ListModule.prototype.loadSortSettings = function ()
{
	var path = "folders/entryid_"+this.entryid+"/sort";
	
	data = webclient.settings.get(path);

	// Save the rows which are to be sorted in an array.
	var sortColumns = new Array();
	for(var i in data){
		if(i != "prototype"){//workarround		
			var column = new Object();
			column["attributes"] = new Object();
			column["attributes"]["direction"] = data[i];
			column["_content"] = i;
			// push column in a sortColumns array
			sortColumns.push(column);
		}
	}

	// If sortColumns is not available then return false otherwise return sortColumns.
	if(sortColumns.length <= 0){
		var result = false;
	}else{
		var result = sortColumns;
	}
	return result;
}
/**
 * This method is called when a dragdrop event has been started on an element 
 * that has this moduleObject associated with it.
 */ 
ListModule.prototype.dragEventDown = function(){
	this.dragSelectedMessages = this.getSelectedMessages();
}
/**
 * This method is called when a dragdrop event has ended on an element that has 
 * this moduleObject associated with it.
 */ 
ListModule.prototype.dragEventUp = function(){
	this.dragSelectedMessages = false;
}

ListModule.prototype.isMessageSelected = function(id){
	for(var i=0;i<this.selectedMessages.length;i++){
		if(this.selectedMessages[i] == id){
			return true;
		}
	}
	return false;
}

/**
 * Returns the row numbers of all selected messages.
 *
 * If 'selectedid' is specified, then the function returns the rows that
 * should be acted upon during a context menu operation. The selectedid must
 * be specified because when the user right-clicks a previously selected
 * message, the operation should be done on all selected messages, but if
 * the right-click was done on a non-selected message, then THAT message
 * should be acted upon.
 */ 
ListModule.prototype.getSelectedMessages = function(selectedid)
{
	var result = new Array;
	
	if (typeof selectedContextMessage != undefined && !selectedid){
		selectedid = this.selectedContextMessage;
	}
	if (this.selectedMessages.length == 0){
		if (selectedid)
			result[0] = selectedid;
	} else {
		
		if (selectedid){
			// check if selectedid is within selectedMessages, then we will return the selectedMessages
			var selectedItemFound = false;

			for(var i=0; i<this.selectedMessages.length;i++){
				if(this.selectedMessages[i] == selectedid){
					selectedItemFound = true;
				}
			}

			if(!selectedItemFound){
				// return selectedContextMessage
				result[0] = selectedid;
			} else {
				// return selectedMessages
				result = this.selectedMessages;
			}
		} else {
			// return selectedMessages
			result = this.selectedMessages;
		}
	}
	return result;
}

/**
 * Returns the row number of the topmost selected item
 */
ListModule.prototype.getSelectedRowNumber = function() {
	var selected = this.getSelectedMessages();	
	var top = selected[0];

	return this.viewController.getRowNumber(top);
}

/**
 * Returns the rowid of the given row number
 */
ListModule.prototype.getMessageByRowNumber = function(rownum)
{
	return this.viewController.getElemIdByRowNumber(rownum);
}

/**
 * Returns the number of rows in the table
 */
ListModule.prototype.getRowCount = function()
{
	return this.viewController.getRowCount();
}

/**
 * Returns a list of unique IDs of all the selected rows
 */
ListModule.prototype.getSelectedIDs = function()
{
	var result = new Array;
	for(var i=0; i<this.selectedMessages.length; i++) {
		result.push(this.entryids[this.selectedMessages[i]]);
	}
	
	return result;
}

/**
* Standard event handler for opening items
*
* message_type is the type of message "appointment", "task", "contact" etc (usally a part of the message_class)
*/
ListModule.prototype.onOpenItem = function(entryid, message_type)
{
	this.setReadFlag(entryid, "read,"+(this.sendReadReceipt(entryid)?"receipt":"noreceipt"));

	var uri = DIALOG_URL+"task=" + message_type + "_standard&storeid=" + this.storeid + "&parententryid=" + this.entryid + "&entryid=" + entryid;
	webclient.openWindow(this, message_type, uri);
}

ListModule.prototype.updateItemProps = function(item)
{
	var entryid = dhtml.getXMLValue(item, this.uniqueid, null)
	if (entryid){
		this.itemProps[entryid] = new Object();
		for(var j=0;j<item.childNodes.length;j++){
			if (item.childNodes[j].nodeType == 1){
				var prop_name = item.childNodes[j].tagName;
				var prop_val = dom2array(item.childNodes[j]);
				if (prop_val!==null){
					this.itemProps[entryid][prop_name] = prop_val;
				}
			}
		}
	}
}

ListModule.prototype.deleteItemProps = function(entryid)
{
	delete this.itemProps[entryid];
}



// Function which creates input fields for editing tasks.
ListModule.prototype.CreateEditFields = function (moduleObject, element, event)
{
	var value = '';	
	var rowValues = moduleObject.itemProps[moduleObject.entryids[element.id]];
	
	//set flag for removing css class 'complete' from each column
	var check = moduleObject.itemProps[moduleObject.entryids[element.id]]["complete"];
	
	//insertcolumn properties
	var inputprops = moduleObject.inputproperties;		

	setTimeout( function() { 
		if (moduleObject.dblclick == true) {
			moduleObject.dblclick = false;
			return;
		}
	
	
		//create input type fields for each column properties... only if module has quick-add functionality
		if (element.getElementsByTagName("input").length <= 1 && inputprops.length > 0) {
			
			//remove drag event on item row...
			dhtml.removeEvent(element, "mousedown", eventDragDropMouseDownDraggable);
			
			//remove click event on status checkbox
			if (dhtml.getElementById("property_module"+ moduleObject.id +"_"+ element.id +"_complete")) {
				dhtml.removeEvent(dhtml.getElementById("property_module"+ moduleObject.id +"_"+ element.id +"_complete"), "click", eventListChangeCompleteStatus);
			}
			
			//get tableview object...
			tableview = new TableView();
			
			for (var i=0; i<inputprops.length; i++) {
				value = '';
				
				//get column element for editing task...
				colelement = dhtml.getElementById("property_module"+ moduleObject.id +"_"+ element.id +"_"+ inputprops[i].name);			
				moduleObject.previousvalue[colelement.id] = colelement.innerHTML;
				
				if (rowValues[inputprops[i].name]) {
					if (inputprops[i].name == "percent_complete") {
						value = rowValues[inputprops[i].name] * 100 +"%";
						if (rowValues[inputprops[i].name] == 1) check = 1;
					} else {
						value = rowValues[inputprops[i].name];
					}
				}
				
				//render input type fields for column...
				tableview.renderInputColumn(true, moduleObject.id, colelement, inputprops[i].type, inputprops[i].id, value, false, inputprops[i].name, inputprops[i].readonly);
			
				//if task was marked as complete, then remove css class 'complete' from every column
				if (check == 1) {
					dhtml.removeClassName(colelement,"complete");
				}
				
				var inputElement = colelement.getElementsByTagName("input")[0];
				if (inputElement) {
					dhtml.addEvent(moduleObject.id, inputElement , "click", eventInputFieldClick);			
				}
				
				//setup datepicker for dates 
				if (inputprops[i]["type"] == "datepicker") { 				
					setcal("editprops_module"+ moduleObject.id +"_"+ inputprops[i]["id"], "cal_editprops_module"+ moduleObject.id +"_"+ inputprops[i]["id"]);
				}
			}
			
			//A message is put into editable form, so set 'editMessage' variable...
			moduleObject.editMessage = element.id;
		}
	}, 500);
}

/**
 * getDragDropTargetCallback
 * 
 * This function returns the correct event function to handle the dragdrop event. 
 * 
 * @return function dragdrop even function
 */
ListModule.prototype.getDragDropTargetCallback = function(){
	if(eventListDragDropTarget){
		return eventListDragDropTarget;
	}else{
		return false;
	}
}

/**
 * Receives callback from the categories window
 */
 
function categoriesCallBack(categories, userdata)
{
	var entryid = userdata.entryid;
	var module = userdata.module;
	
	module.setCategories(entryid, categories);		
}

/**
 * All the events for this module are defined below. In the "init" function of this 
 * module are most of these events set. Every event receives three parameters.
 * @param obejct moduleObject the module object
 * @param object element the element on which the event fired
 * @param object event the event object 
 */ 
 
function eventListMouseDownMessage(moduleObject, element, event)
{
	if(!event){
		event = new Object();
	}

	// Check if contextmenu is opened. If so, remove the class on the element.
	// This check is build in, because if the same element is clicked as the contextmenu 
	// element, the style brakes. With this check the style is correct and this message
	// is selected.
	eventListCheckSelectedContextMessage(moduleObject);

	if (event.button == 0 || event.button == 1 || !event.button) {
		/**
		 * This lines seems to get the first classname and append it with "selected". So for normal 
		 * table with rows it appends "row" to "rowselected". For notes it appends "large_view" to 
		 * "large_viewselected". For contact card view it appends "contact" to "contactselected".
		 */
		var className = (element.className.indexOf(" ") > 0?element.className.substring(0, element.className.indexOf(" ")):element.className) + "selected";

		if (event.ctrlKey) {
				// Deselect previously selected item
			if (element.className.indexOf(className) > 0) {
				// Deselect previously selected item
				dhtml.deselectElement(element.id, className);
				
				// Search for current element in list of selected items.
				var elementIndex = -1;
				for(var i = 0; i < moduleObject.selectedMessages.length; i++)
				{
					if(moduleObject.selectedMessages[i] == element.id) {
						elementIndex = i;
					}
				}
				
				// Remove focussed item from list of selected items
				if(elementIndex >= 0) {
					moduleObject.selectedMessages.splice(elementIndex, 1);
				}
			// Current element not selected
			} else {
				// Select previously unselected item
				dhtml.selectElement(element.id, className);
				moduleObject.selectedMessages.push(element.id);
				moduleObject.selectedFirstMessage = element.id;
			}
			// Set cursor position to focussed element
			moduleObject.viewController.setCursorPosition(element.id);
		} else if(event.shiftKey) {
			// Deselect all messages, set cursor position and select from first item till focussed item.
			dhtml.deselectElements(moduleObject.selectedMessages, className);
			moduleObject.viewController.setCursorPosition(element.id);
			moduleObject.selectedMessages = dhtml.selectRange(moduleObject.selectedFirstMessage, moduleObject.viewController.getCursorPosition(), className);
		// No shift or control used. Only mousedown or keyboard up/down
		} else {
			if (!moduleObject.isMessageSelected(element.id)) {
				dhtml.deselectElements(moduleObject.selectedMessages, className);
				dhtml.selectElement(element.id, className);
				moduleObject.selectedMessages = new Array(element.id);
			}
			moduleObject.selectedFirstMessage = element.id;
			moduleObject.viewController.setCursorPosition(element.id);
		}

		// clear the text selection on document.
		dhtml.clearBodySelection();
	}
	
	// save changes and dactivate editmode, if 'mousedown' on other item...
	if (moduleObject.editMessage !== false && moduleObject.editMessage !== element.id) {
		// here we have to pass element id of message which is in edit mode
		// not the current element
		if (moduleObject.SubmitMessage(moduleObject, dhtml.getElementById(moduleObject.editMessage), event)){
			moduleObject.removeinputfields(moduleObject, element, event);
		}
	}

	// As 'mousedown' event is also registered for divelement we don't want the event to bubble to divelement.
	// only cancel bubbling when quick edit mode is active
	if(typeof moduleObject.editMessage != "undefined" && moduleObject.editMessage !== false) {
		event.stopPropagation();
	}
}


function eventListMouseUpMessage(moduleObject, element, event)
{
	if(!event) {
		event = new Object();
	}
	if (event.button == 0 || event.button == 1 || !event.button) {
		var className = (element.className.indexOf(" ") > 0?element.className.substring(0, element.className.indexOf(" ")):element.className) + "selected";

		if ((typeof(dragdrop) == "undefined" || !dragdrop.targetover) && !event.ctrlKey && !event.shiftKey) {

			moduleObject.sendEvent("selectitem", moduleObject.entryids[element.id]);
				
			if (moduleObject.isMessageSelected(element.id) && moduleObject.selectedMessages.length != 1){
				dhtml.deselectElements(moduleObject.selectedMessages, className);
				dhtml.selectElement(element.id, className);

				moduleObject.selectedMessages = new Array(element.id);
			}
		}
		
		/**
		 * Dont put item into editmode,
		 * when special keyes are pressed.
		 * e.g PgDn, PgUp etc.
		 */
		if (event.type != "keydown") {
			if (moduleObject.selectedMessages.length == 1 && !moduleObject.editMessage) {
				/**
				 * Check to see if the the message we have clicked on has been selected
				 * by the previous click and that we are not dragging anything.
				 */
				if (moduleObject.selectedMessages[0] === moduleObject.prevselectedMessage && !(typeof dragdrop != "undefined" && dragdrop.attached === true)) {
					moduleObject.CreateEditFields(moduleObject, element, event);
				}
			}
		}
		
		//assign newly selected item id to 'preveselectedMessage' variable... 
		moduleObject.prevselectedMessage = element.id;
	}
}

function eventListDblClickMessage(moduleObject, element, event)
{	

	moduleObject.dblclick = true;
	
	if (moduleObject.editMessage && event.keyCode == 13) {
		//set drag and drop event for tasks.
		dhtml.addEvent(moduleObject.id, element, "mousedown", eventDragDropMouseDownDraggable);

		//set click event so that task is saved as complete when user selects the complete flag...
		if (dhtml.getElementById("property_module"+ moduleObject.id +"_"+ element.id +"_complete")) {
			dhtml.addEvent(moduleObject.id, dhtml.getElementById("property_module"+moduleObject.id +"_"+ element.id +"_complete"), "click", eventListChangeCompleteStatus);
		}
		
		if (moduleObject.SubmitMessage(moduleObject, element, event)){
			moduleObject.dblclick = false;
			moduleObject.editMessage = false;
		}
	} else if(!moduleObject.editMessage) {
		var messageClass = false;
		var classNames = element.className.split(" ");
	
		for(var index in classNames)
		{
			if(classNames[index].indexOf("ipm_") >= 0 && messageClass==false) {
				messageClass = classNames[index].substring(classNames[index].indexOf("_") + 1);
			}
		}
		moduleObject.sendEvent("openitem", moduleObject.entryids[element.id], messageClass);
	}
}

function eventListContextMenuMessage(moduleObject, element, event)
{
	var className = (element.className.indexOf(" ") > 0?element.className.substring(0, element.className.indexOf(" ")):element.className);
	var classNameContextMenu = className + "contextmenu";

	if(moduleObject.selectedContextMessage) {
		var message = dhtml.getElementById(moduleObject.selectedContextMessage);
		
		if(message) {
			if(message.className.indexOf(classNameContextMenu) > 0) {
				dhtml.removeClassName(message, classNameContextMenu);
			}
		}
	}
	
	if(element.className.indexOf(className + "selected") < 0) {
		element.className += " " + classNameContextMenu;
	}

	moduleObject.selectedContextMessage = element.id;
	
	var items = new Array();
	var removeMenuItems = new Array();

	if (moduleObject.itemProps[moduleObject.entryids[moduleObject.selectedContextMessage]]){
		var props = moduleObject.itemProps[moduleObject.entryids[moduleObject.selectedContextMessage]];
		if (props.message_class && props.message_class == "IPM.DistList"){
			removeMenuItems.push("createmail");
		}
	}

	var selection = moduleObject.getSelectedMessages();
	var selectionHasUnread = false;
	var selectionHasRead = false;
	for(i in selection){
		var el = dhtml.getElementById(selection[i]);

		// Check for read/unread (only for mail and tasks)
		if(el.className.indexOf("mail") > 0 || el.className.indexOf("task") > 0 ) {
			if(el.className.indexOf("message_unread") > 0) {
				selectionHasUnread = true;
			} else {
				selectionHasRead = true;
			}
		}
		if (selectionHasRead && selectionHasUnread)
			break; // no need to check the other messages
	}

	if (selectionHasRead && !selectionHasUnread) {
		removeMenuItems.push("markread");
	}

	if (selectionHasUnread && !selectionHasRead) {
		removeMenuItems.push("markunread");
	}

	if (webclient.hierarchy && webclient.hierarchy.isSpecialFolder("junk", moduleObject.entryid)){
		removeMenuItems.push("junk");
	}

	for(var i in moduleObject.contextmenu) {
		var item = moduleObject.contextmenu[i];
		for(var j=0; j<removeMenuItems.length; j++){
			if(item["id"] == removeMenuItems[j]){
				item = false;
				break;
			}
		}
		if (item){
			items.push(item);
		}
	}

	webclient.menu.buildContextMenu(moduleObject.id, element.id, items, event.clientX, event.clientY);
}

function eventListCheckSelectedContextMessage(moduleObject, element, event)
{
	// only react on click events and no events, this is a workaround, we get events here from body (mouseup)
	if((!event || event.type == "click") && moduleObject.selectedContextMessage) {
		var message = dhtml.getElementById(moduleObject.selectedContextMessage);
		
		if(message) {
			var className = (message.className.indexOf(" ") > 0?message.className.substring(0, message.className.indexOf(" ")):message.className) + "contextmenu";
			if(message.className.indexOf(className) > 0) {
				message.className = message.className.substring(0, message.className.indexOf(className));
			}
		}
		
		moduleObject.selectedContextMessage = false;
	}
}

function eventListNewMessage(moduleObject, element, event)
{
	if(element.parentNode.id == "defaultmenu") {
		element.parentNode.style.display = "none";
	}
	
	var messageClass = false;
	var classNames = element.className.split(" ");
	
	for(var index in classNames)
	{
		if(classNames[index].indexOf("icon_") >= 0) {
			messageClass = classNames[index].substring(classNames[index].indexOf("_") + 1);
		}
	}

	var parententryID = moduleObject.entryid;
	var storeID = moduleObject.storeid;

	if(messageClass) {
		var extraParams = "";
		if (messageClass == "appointment"){
			// Check implemented mainly for the multiusercalendar
			if(!parententryID){
				parententryID = webclient.hierarchy.defaultstore.defaultfolders.calendar;
			}
			var dtmodule = webclient.getModulesByName("datepickerlistmodule");
			if (dtmodule[0] && dtmodule[0].selectedDate){
				if (!new Date(dtmodule[0].selectedDate).isSameDay(new Date())){
					var hourCount = webclient.settings.get("calendar/workdaystart",9 * 60) / 60;
					var newAppDateTimeStamp = addHoursToUnixTimeStamp(dtmodule[0].selectedDate / 1000, hourCount);
					extraParams = "&date=" + newAppDateTimeStamp;
				}
			}
		} else if (messageClass == "createmail"){
			// Select default store when creating new mail while other's Inbox is opened
			storeID = webclient.hierarchy.defaultstore.id;
			parententryID = webclient.hierarchy.defaultstore.defaultfolders.outbox;
		}

		webclient.openWindow(moduleObject, messageClass, DIALOG_URL+"task=" + messageClass + "_standard&storeid=" + storeID + "&parententryid=" + parententryID + extraParams);
	}
}

function eventListDeleteMessages(moduleObject, element, event)
{
	var selectedMessages = moduleObject.getSelectedMessages();
	if(selectedMessages.length > 0) {
		moduleObject.deleteMessages(selectedMessages);
	} else {
		alert(_("Please select a message to delete."));
	}
}

function eventListCopyMessages(moduleObject, element, event)
{
	moduleObject.showCopyMessagesDialog();
}

function eventListPrintMessage(moduleObject, element, event)
{
	if(moduleObject.getModuleName() == "datepickerlistmodule") {
		moduleObject.printList(moduleObject.entryid);
	} else if(moduleObject.entryids && moduleObject.selectedMessages[0]){
		var item = moduleObject.entryids[moduleObject.selectedMessages[0]];
		moduleObject.printItem(item);
	}
}

function eventListShowAddressbook(moduleObject, element, event)
{
    // Although this window is not modal, we're using the modal addressbook dialog anyway
    webclient.openWindow(moduleObject, 'addressbook', DIALOG_URL+'task=addressbook_modal&storeid=' + moduleObject.storeid, 550, 410, true);    
}

function eventListMouseOverFlag(moduleObject, element, event)
{
	element.className += "_over";
}

function eventListMouseOutFlag(moduleObject, element, event)
{
	if(element.className.indexOf("_over") > 0) {
		element.className = element.className.substring(0, element.className.indexOf("_over"));
	}
}

function eventListChangeFlagStatus(moduleObject, element, event)
{
	var flagStatus = 1;
	var flagIcon = 0;

	if(element.className.indexOf("complete") > 0 || element.className.indexOf("flag_over") > 0) {
		flagStatus = 2;
		flagIcon = 6;
	}

	moduleObject.flagStatus(moduleObject.entryids[element.parentNode.id], flagStatus, flagIcon);
}

function eventListChangeReadFlag(moduleObject, element, event)
{
	if(element.parentNode.className.indexOf("ipm_readmail") > 0){
		var flag = "unread";
		if(element.parentNode.className.indexOf("message_unread") > 0) {
			flag = "read,"+(moduleObject.sendReadReceipt(moduleObject.entryids[element.parentNode.id])?"receipt":"noreceipt");
		}
		moduleObject.setReadFlag(moduleObject.entryids[element.parentNode.id], flag);
	}
}

function eventListChangeCompleteStatus(moduleObject, element, event)
{
	var checkbox = element.getElementsByTagName("input")[0];

	if(checkbox) {
		moduleObject.completeStatus(moduleObject.entryids[element.parentNode.id], checkbox.checked);
	}
}

function eventListChangePage(moduleObject, element, event)
{
	if(element.className.indexOf("value_") > 0) {
		var classNames = element.className.split(" ");

		var page = 0;
		for(var i in classNames)
		{
			if(classNames[i].indexOf("value_") >= 0) {
				page = classNames[i].substring(classNames[i].indexOf("_") + 1);
			}
		}
		moduleObject.changePage(page);
	} else if (element.className.indexOf("prev") > 0) {
		var page = Math.floor(moduleObject.rowstart / moduleObject.rowcount) - 1;
		if (page>=0) {
			moduleObject.changePage(page);
		}
	} else if (element.className.indexOf("next") > 0) {
		var page = Math.floor(moduleObject.rowstart / moduleObject.rowcount) + 1;
		if (page<=Math.floor(moduleObject.totalrowcount/moduleObject.rowcount)) {
			moduleObject.changePage(page);
		}
	}
}

function eventListChangeView(moduleObject, element, event)
{
	if(element.className.indexOf("value_") > 0) {
		var classNames = element.className.split(" ");

		var value = moduleObject.defaultview;
		for(var i in classNames)
		{
			if(classNames[i].indexOf("value_") >= 0) {
				value = classNames[i].substring(classNames[i].indexOf("_") + 1);
			}
		}

		moduleObject.destructor();
		moduleObject.initializeView(value);
		moduleObject.list();
		moduleObject.resize();
	}
}

function eventListColumnSort(moduleObject, element, event)
{
	var old_sortColumn = moduleObject.viewController.viewObject.sortColumn;
	var old_sortDirection = moduleObject.viewController.viewObject.sortDirection;

	var sortColumn = element.id.substring(element.id.indexOf("_") + 1);
	if(element.id.indexOf("sort") > 0) {
		sortColumn = element.id.substring(element.id.indexOf("_") + 1, element.id.indexOf("sort") - 1);
	}
	
	var sortDirection = "";
	// change direction only through menu or when you click the already sorted column
	if (dhtml.hasClassName(event.target,"menuitem") || sortColumn==old_sortColumn){
		if(element.id.indexOf("sort") > 0) {
			if(element.id.indexOf("sort_asc") > 0) {
				sortDirection = "desc";
			}
		}
	}else{
		sortDirection = old_sortDirection;
	}
	
	if(!sortDirection)
		sortDirection = "asc";
	
	var sortSaveList = Object();
	sortSaveList[sortColumn] = sortDirection
	
	/**
	 * flag status column value depends on values of flag_status and flag_icon properties,
	 * so do sorting on both properties.
	 */
	if(sortColumn == "flag_icon")
		sortSaveList["flag_status"] = sortDirection;

	moduleObject.saveSortSettings(sortSaveList);

	//Check if there is any restriction on sorting
	var name = dhtml.getElementById("name");
	if(name) {
		moduleObject.list(false, false, name.value);
	} else {
		moduleObject.list();
	}
}

function eventListColumnContextMenu(moduleObject, element, event)
{
	var items = new Array();
	if(moduleObject.enableSorting) {
		items.push(webclient.menu.createMenuItem("sort_ascending", _("Sort Ascending"), false, eventListColumnContextSortAsc));
		items.push(webclient.menu.createMenuItem("sort_descending", _("Sort Descending"), false, eventListColumnContextSortDesc));
	}
	if(moduleObject.enableVariableColumns) {
		items.push(webclient.menu.createMenuItem("seperator", ""));
		items.push(webclient.menu.createMenuItem("columndelete", _("Delete this column"), false, eventListColumnDelete));
		items.push(webclient.menu.createMenuItem("seperator", ""));
		items.push(webclient.menu.createMenuItem("fieldchooser", _("Field Chooser"), false, eventListFieldChooser));
	}

	if(moduleObject.enableSorting || moduleObject.enableVariableColumns)
		webclient.menu.buildContextMenu(moduleObject.id, element.id, items, event.clientX, event.clientY);
}

function eventListColumnContextSortAsc(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	
	var column = dhtml.getElementById(element.parentNode.elementid);
	if(column.id.indexOf("sort") > 0) {
		column.id = column.id.substring(0, column.id.indexOf("sort") - 1);
	}
	
	eventListColumnSort(moduleObject, column, event);
}

function eventListColumnContextSortDesc(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	
	var column = dhtml.getElementById(element.parentNode.elementid);
	if(column.id.indexOf("sort_asc") <= 0) {
		column.id = column.id + "_sort_asc";
	}

	eventListColumnSort(moduleObject, column, event);
}

function eventListColumnDelete(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	
	if(!moduleObject.columns) {
		moduleObject.columns = new Array();
	}
	
	var columnElement = dhtml.getElementById(element.parentNode.elementid);
	var sortColumn = columnElement.id.substring(columnElement.id.indexOf("_") + 1);
	if(columnElement.id.indexOf("sort") > 0) {
		sortColumn = columnElement.id.substring(columnElement.id.indexOf("_") + 1, columnElement.id.indexOf("sort") - 1);
	}
	
	var column = new Object();
	column["id"] = sortColumn;
	column["action"] = "delete";
	//get other columns
	var columnList = moduleObject.loadFieldSettings();
	columnList.push(column);
	//save columns
	moduleObject.saveFieldSettings(columnList);
	//display comlumns
	moduleObject.list();
}

function eventListFieldChooser(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	/**
	 * If field chooser is opened by main window then take webclient as its parent window.
	 * If field chooser is opened from some dialog box then take it's parentwebclient object to open.
	 */
	if (typeof parentWebclient != "undefined")
		parentWebclient.openModalDialog(moduleObject, "fieldchooser", DIALOG_URL+"task=fieldchooser_modal", 550, 470, fieldChooserCallBack, moduleObject);
	else
		webclient.openModalDialog(moduleObject, "fieldchooser", DIALOG_URL+"task=fieldchooser_modal", 550, 470, fieldChooserCallBack, moduleObject);
}

function eventListDragDropTarget(moduleObject, targetElement, element, event)
{

	// Destination entryid
	var folder = targetElement.parentNode.parentNode.id;

	if (folder == "main"){
		// this is the maillist, ignore the drop
		return;
	}

	if(typeof moduleObject.dragSelectedMessages == "object" && moduleObject.dragSelectedMessages[0] != false && moduleObject.dragSelectedMessages.length > 1){
		var selectedMessages = moduleObject.dragSelectedMessages;
	}else{
		var selectedMessages = moduleObject.getSelectedMessages();
	}
	if(typeof selectedMessages != "object"){
		selectedMessagesArr = new Array();
		selectedMessagesArr[0] = selectedMessages;
		selectedMessages = selectedMessagesArr;
	}

	// Flag for checking whether target is waste basket (Deleted items folder) or not.
	var targetIsWasteBasket = false;

	var folderObject = webclient.hierarchy.getFolder(folder);

	// get target folder entryid
	var targetStoreID = folderObject.storeid;
	var targetEntryID = folderObject.entryid;

	// get target folder properties
	var targetFolderProperties = webclient.hierarchy.getFolder(targetEntryID);
	var targetFolderContainerClass = targetFolderProperties.container_class;
	var targetFolderContainerClassParts = targetFolderContainerClass.split('.') ;

	if(targetFolderProperties["entryid"] == webclient.hierarchy.defaultstore.defaultfolders.wastebasket) {
		// allow copy/move operation for all items if destination folder is deleted items
		targetIsWasteBasket = true;
	}

	// Message entryids
	var entryid = Array();
	for(var i=0;i<selectedMessages.length;i++){
		if (moduleObject.entryids[selectedMessages[i]]) {
			if(targetIsWasteBasket) {
				// If target is waste basket (Deleted items folder) then move all items to entryid array
				entryid.push(moduleObject.entryids[selectedMessages[i]]);
			} else {
				var selectedItemMessageClassParts = moduleObject.itemProps[moduleObject.entryids[selectedMessages[i]]].message_class.split(".");
				if(targetFolderContainerClassParts[1] == selectedItemMessageClassParts[1]) {
					// If target folder is of same message class as selected item's message class then move item to entryid array
					entryid.push(moduleObject.entryids[selectedMessages[i]]);
				} else if (selectedItemMessageClassParts[1] == "Schedule" && targetFolderContainerClassParts[1] == "Note") {
					/**
					 * If selected item's message class is IPM.Schedule.Meeting.Request 
					 * then allow it to move in Note folder.
					 */
					entryid.push(moduleObject.entryids[selectedMessages[i]]);
				} else if (selectedItemMessageClassParts[0] == "REPORT" && targetFolderContainerClassParts[1] == "Note") {
					/**
					 * If selected item's message class is of report type
					 * REPORT.IPM.Note.NDR -> undelivered mail.
					 * REPORT.IPM.Note.IPNNRN -> unread notification mail.
					 * REPORT.IPM.Note.IPNRN -> read notification mail.
					 * then allow it to move in Note folder.
					 */
					entryid.push(moduleObject.entryids[selectedMessages[i]]);
				} else if (selectedItemMessageClassParts[1] == "DistList" && targetFolderContainerClassParts[1] == "Contact") {
					/**
					 * If selected item's message class is IPM.DistList 
					 * then allow it to move in Contact folder.
					 */
					entryid.push(moduleObject.entryids[selectedMessages[i]]);
				}
			}
		}
	}
	
	if(folder != moduleObject.entryid && folderObject && entryid.length > 0) {
		moduleObject.copyMessages(folderObject.storeid, folder, "move", true, entryid);
	} else if(entryid.length == 0) {
		/**
		 * TODO: When there multiple messages of different classes are dragged/dropped
		 * from deleted items, It just allows to transfer messages that are type of destination messages.
		 * for other it is not showing any error messages.
		 */
		alert(_("Can not move selected items to destination folder."));
	}
}

function eventListContextMenuOpenMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	var message = dhtml.getElementById(element.parentNode.elementid);

	if(message) {
		eventListDblClickMessage(moduleObject, message, event);
	}
	
	eventListCheckSelectedContextMessage(moduleObject);
}

function eventListContextMenuPrintMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";

	moduleObject.printItem(moduleObject.entryids[element.parentNode.elementid]);

	eventListCheckSelectedContextMessage(moduleObject);
}

function eventListContextMenuCategoriesMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	var callbackdata = new Object();
	callbackdata.module = moduleObject;
	callbackdata.entryid = moduleObject.entryids[element.parentNode.elementid];
	webclient.openModalDialog(moduleObject, "categories", DIALOG_URL+"task=categories_modal&storeid=" + moduleObject.storeid + "&parententryid=" + moduleObject.entryid + "&entryid=" + moduleObject.entryids[element.parentNode.elementid], 350, 370, categoriesCallBack, callbackdata);
}

function eventListContextMenuMessageOptions(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	webclient.openModalDialog(moduleObject, "options", DIALOG_URL+"task=messageoptions_modal&storeid=" + moduleObject.storeid + "&parententryid=" + moduleObject.entryid + "&entryid=" + moduleObject.entryids[element.parentNode.elementid], 460, 420);
}

function eventListContextMenuDeleteMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	var items = moduleObject.getSelectedMessages(element.parentNode.elementid);
	for(i in items){
		moduleObject.deleteMessage(moduleObject.entryids[items[i]], items[i]);
	}
	eventListCheckSelectedContextMessage(moduleObject);
}

function eventListContextMenuMoveJunkMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	var hierarchy =  webclient.hierarchy;
	var destinationFolder = hierarchy.getStore(moduleObject.storeid).defaultfolders["junk"];

	// change flag always to read after move to junk
	var items = moduleObject.getSelectedMessages(element.parentNode.elementid);
	for(i in items){
		moduleObject.setReadFlag(moduleObject.entryids[items[i]], "read,noreceipt");
	}

	moduleObject.copyMessages(moduleObject.storeid, destinationFolder, "move")
	eventListCheckSelectedContextMessage(moduleObject);
}

function eventListContextMenuCopyMessage(moduleObject, element, event)
{
	element.parentNode.style.display = "none";
	webclient.openModalDialog(moduleObject, "copymessages", DIALOG_URL+"task=copymessages_modal&storeid="+moduleObject.storeid, 300, 300);
	eventListCheckSelectedContextMessage(moduleObject);
}

function fieldChooserCallBack(result, module)
{
	var properties = result;
	
	module.saveFieldSettings(properties);
	module.columns = properties;	
	module.list(true);
	
	//If the user has selected 'open inbox at startup',then to save column settings while login we 
	//set inbox storid and entryid in  folders settings.
	if(module.title == "Inbox"){
		webclient.settings.set("folders/entryid_inbox/entryid",module.entryid);
		webclient.settings.set("folders/entryid_inbox/storeid",module.storeid);
	}
}

function eventInputFieldClick(moduleObject, element, event)
{
	if (element.type == "checkbox") {
		percentchange(moduleObject.id, element.id.substring(0,element.id.indexOf("_")));
	}	
	
	if(element.id == "insertprops_module"+ moduleObject.id +"_subject" && element.value == _("Click here to add a new item")) {
		element.value = "";
	}

	if (!element.readOnly) {
		element.focus();
		// also maintain focus on input field using inputmanager
		webclient.inputmanager.handleFocus({"type":"blur"});
		webclient.inputmanager.handleFocus({"type":"focus"});
	}
}

//Function which saves the task
function eventClickSaveMessage (moduleObject, element, event)
{	
	event.stopPropagation();
	var subject = dhtml.getElementById("insertprops_module"+moduleObject.id+"_subject");
	
	//save message only if enter key is pressed or save button is clicked.
	if (event.keyCode == 13 || event.type == "click") {
		
		if (subject) {
			//check subject field is filled properly	
			switch(subject.value)
			{
				case "":
				case _("Click here to add a new item"):
					alert(_("Fill in the Subject"));
					return true;
				default:
				    if (subject.value.trim().length == 0) {
				    	alert(_("Fill in the Subject"));
						return true;
				    }
			}
		}
	
		//find parent tr node to pass it to SubmitMessage() function
		while (element = element.parentNode) {
			if (element.tagName == "TR") {
				break;
			}
		}
		if (moduleObject.SubmitMessage(moduleObject, element)){
			var form = dhtml.getElementById("insertmessage");

			if (form) {
				form.reset();
				form.blur();
			}
		}
	}
	
	//Reset form when ESC button is pressed...
	if (event.keyCode == 27) {		
		var form = dhtml.getElementById("insertmessage");
		if (form) {
			form.reset();
			form.blur();
		}
		
		var showimp = dhtml.getElementById("module"+ moduleObject.id +"_importance");
		if (showimp) {		
			showimp.className = "message_icon icon_norepeat icon_taskarrow";
		}
	}	
}

//Function which removes input fields
ListModule.prototype.removeinputfields = function(moduleObject, element, event)
{		
	var row = dhtml.getElementById(moduleObject.editMessage);
	var checked="";

	if (row && row != element) {		
		var importance = moduleObject.itemProps[moduleObject.entryids[row.id]]["importance"];
		var column = dhtml.getElementById("property_module"+ moduleObject.id +"_"+ row.id +"_importance");
		column.className = "rowcolumn message_icon " + moduleObject.tooltip["importance"]["css"][importance];
		
		for (var j = 0; j < row.cells.length; j++) {
			row.cells[j].innerHTML = moduleObject.previousvalue[row.cells[j].id];
		}
		
		//set drag and drop event for tasks.
		dhtml.addEvent(moduleObject.id, row, "mousedown", eventDragDropMouseDownDraggable);

		//set click event so that task is saved as complete when user selects the complete flag...
		if (dhtml.getElementById("property_module"+moduleObject.id +"_"+ row.id +"_complete")) {
			dhtml.addEvent(moduleObject.id, dhtml.getElementById("property_module"+moduleObject.id +"_"+ row.id +"_complete"), "click", eventListChangeCompleteStatus);	
		}
		
		moduleObject.editMessage = false;		
		
		//add css class 'complete' if task was set as complete...		
		if (moduleObject.itemProps[moduleObject.entryids[row.id]]["complete"] == 1) {
			for (var i = 0; i < row.cells.length; i++) {
				if (!dhtml.hasClassName(row.cells[i],"message_icon")){				
					dhtml.addClassName(row.cells[i],"complete");
				}
			}
		}
	}
}

//Function which deselects the messages...
function eventDeselectMessages(moduleObject, element, event)
{
	var deselect = new Array();

	//deselect messages visually i.e change class of selected messages.
	for (var i = 0; i < moduleObject.selectedMessages.length; i++) {
		dhtml.deselectElement(moduleObject.selectedMessages[i],"rowselected");
		deselect[i]=moduleObject.selectedMessages[i];
	}

	//delete or remove selected message ids from 'selectedMessages' variable...
	for (var i = 0; i < deselect.length; i++) {
		for (var j = 0; j < moduleObject.selectedMessages.length; j++) {
			if (deselect[i] == moduleObject.selectedMessages[j]) {
				moduleObject.selectedMessages.splice(j,1);
			}
		}
	}
	moduleObject.prevselectedMessage = false;
	event.stopPropagation();
}

//Function which creates importance menu
function eventClickChangeImportance(moduleObject, element, event)
{
	event.stopPropagation();
	
	
	//show importance menu only on left click mouseevent on importance column...
	if (event.button == 0 || event.button == 1) {
		
		//check importance menu is already selected...
		importancemenu = dhtml.getElementById("importancemenu");
		if (importancemenu) {
			//remove menu if selected...
			dhtml.showHideElement(importancemenu, event.clientX, event.clientY, true);
		}
		
		//create menu for importance and append it to document body...
		importancemenu = dhtml.addElement(document.body,"div","importancemenu","importancemenu");
		divimportance = "<table cellspacing='0' cellpadding='0' width='65' style='visibility: visible;'><tr class='menurow'><td class='icon icon_norepeat icon_importance_low'/><td>Low</td></tr>";
		divimportance += "<tr class='menurow'><td class='icon icon_norepeat ";

		/**
		 * We want dropdown arrow for Normal Priority
		 * only in those list which has Quickitem ability.
		 */
		if (this.inputproperties.length > 0) {
			divimportance += "icon_taskarrow'/><td>Normal</td></tr>";
		} else {
			divimportance += "'/><td>Normal</td></tr>";
		}
		divimportance += "<tr class='menurow'><td class='icon icon_norepeat icon_importance_high'/><td>High</td></tr></table>";	
		importancemenu.innerHTML = divimportance;
		importancemenu.style.position = "absolute";
		importancemenu.style.display = "block";
		importancemenu.style.left = (event.clientX)- 5 + "px";
		importancemenu.style.top = (event.clientY)- 5 + "px";
		
		rows = importancemenu.getElementsByTagName("tr");
		if (rows) {
			for (var i =0; i < rows.length; i++) {
				dhtml.setEvents(moduleObject.id, rows[i], moduleObject.events["menu"]["importance"]);
			}
		}
		
		//store row id in messageID
		moduleObject.messageID = element.parentNode.id;
	}
}

/**
 * Fucntion stops propagating event for quicktime insert row which is text field in tasks folder.
 * So selection in text field becomes possible
 */
function eventListInsertRowMouseMove(moduleObject, element, event)
{
	event.stopPropagation();
}

/**
 * Fucntion stops propagating event for quicktime row in tasks folder in edit time mode.
 * So selection in text field becomes possible
 */
function eventListRowMouseMove(moduleObject, element, event)
{
	if(this.editMessage !== false)
		event.stopPropagation();
}

/**
* Function which set the IMPORTANCE STATUS...
* @param string messageEntryid	-the entryid of the message
* @param object priorityStatus		-properties of item
*/
ListModule.prototype.importanceStatus = function(messageEntryid, priorityStatus)
{	
	var data = new Object();
	data["store"] = this.storeid;
	data["parententryid"] = this.entryid;
	data["props"] = new Object();
	data["props"]["entryid"] = messageEntryid;
	data["props"]["importance"] = priorityStatus;

	webclient.xmlrequest.addData(this, "save", data);
}

function eventMenuImportanceMouseOver (moduleObject, element, event)
{
	dhtml.addClassName(element,"menuitemover");
}

function eventMenuImportanceMouseOut (moduleObject, element, event)
{
	dhtml.removeClassName(element,"menuitemover");
}

function eventMenuImportanceClick (moduleObject, element, event)
{
	event.stopPropagation();
	importancemenu = dhtml.getElementById("importancemenu");
	
	if (importancemenu) {
		importancemenu.style.display = "none";

		//check if importancemenu is selected for editing task or entering new task...
		if (moduleObject.itemProps[moduleObject.entryids[moduleObject.messageID]]) {
			var columnElement = dhtml.getElementById("property_module"+ moduleObject.id +"_"+ moduleObject.messageID +"_importance");
			columnElement.title = moduleObject.tooltip["importance"]["value"][element.rowIndex];
			moduleObject.previousvalue["editprops_module"+moduleObject.id+"_importance"] = moduleObject.itemProps[moduleObject.entryids[moduleObject.messageID]]["importance"];
			moduleObject.itemProps[moduleObject.entryids[moduleObject.messageID]]["importance"] = element.rowIndex;
			
			/*if message is in edit form, save value in hidden importance field and return from this function bcouz, we want to save
			  priority when user presses ENTER key for saving all fields*/
			if (moduleObject.editMessage) {
				for (var i=0; i<3;i++) {
					if (dhtml.hasClassName(columnElement, moduleObject.tooltip["importance"]["css"][i])) {
						dhtml.removeClassName(columnElement, moduleObject.tooltip["importance"]["css"][i]);
					}
				}			
				dhtml.addClassName(columnElement, moduleObject.tooltip["importance"]["css"][element.rowIndex]);		
				
				//hidden importance input field element
				var importanceElement = dhtml.getElementById("editprops_module"+ moduleObject.id +"_importance");
				importanceElement.value = element.rowIndex;
			} else {
				moduleObject.importanceStatus(moduleObject.itemProps[moduleObject.entryids[moduleObject.messageID]]["entryid"], element.rowIndex);
			}
		} else {
			//Just change css class and importance value if entering new task...
			var importanceElement = dhtml.getElementById("insertprops_module"+ moduleObject.id +"_importance");
			var priority = parseInt(importanceElement.value);
			var className = moduleObject.tooltip["importance"]["css"][priority];
			var columnElement = dhtml.getElementById("module"+ moduleObject.id +"_importance");
			columnElement.title = moduleObject.tooltip["importance"]["value"][element.rowIndex];
			
			dhtml.removeClassName(columnElement, className);		
			importanceElement.value = element.rowIndex;
			dhtml.addClassName(columnElement, moduleObject.tooltip["importance"]["css"][element.rowIndex]);
		}
		
		//After saving importance remove importancemenu from DOM...
		dhtml.showHideElement(importancemenu, importancemenu.Left, importancemenu.Top, true);
		dhtml.executeEvent(dhtml.getElementById("divelement"),"mousedown");
	}
}

function eventListStopBubble(moduleObject, element, event)
{
	if (event.keyCode != 13 && event.keyCode != 27) {
		event.stopPropagation();
		moduleObject.stopbubble = true;
	}
}



/**
 * Function to select the old selected email [if any] again.
 * clears the variable of old selected email's entryid
 */
ListModule.prototype.selectOldSelectedEmail = function()
{
	var oldSelectedMailEntryId = moduleObject.oldSelectedMailEntryId;
	var mailItems = dhtml.getElementsByClassNameInElement(dhtml.getElementById("divelement"),"row", "tr");
	for(var x=0;x<mailItems.length;x++){
		if(mailItems[x].getAttribute("entryid") == oldSelectedMailEntryId){
			// Fire the onmousedown event on the previously selected item. 
			dhtml.executeEvent(mailItems[x], "mousedown");
			dhtml.executeEvent(mailItems[x], "mouseup");
			if(!dhtml.hasClassName(mailItems[x], "rowselected"))
				dhtml.addClassName(mailItems[x], "rowselected");
			break;
		}
	}
	//clear the variable to stop calling this function each time.
	moduleObject.oldSelectedMailEntryId = null;
}

/**
 * Defining a global function to store old selected email's entryid 
 * which is needed to select the same email after reload of list.
 *  
 */
function storeOldSelectedEmailEntryId(){
	var mailmodules = webclient.getModulesByName("maillistmodule");
	if (mailmodules.length>0){
		for(var i=0;i<mailmodules.length;i++){
			if (mailmodules[i].rowstart == 0){
				var mailListElem = dhtml.getElementById("divelement");
				if(mailListElem){ 
					var oldSelectedElement = dhtml.getElementsByClassNameInElement(mailListElem,"rowselected", "tr")[0];
					if(oldSelectedElement){
						mailmodules[i].oldSelectedMailEntryId = oldSelectedElement.getAttribute("entryid");
						break;
					}
				}
			}
		}
	}
}
