/*
 * 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. The use of the logo
 * of Zarafa in Legal Notices is allowed for unmodified and modified
 * versions of the software.
 * 
 * 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/>.
 * 
 */

/**
 * ItemModule
 * The module to load, save and delete one item. 
 */
ItemModule.prototype = new Module;
ItemModule.prototype.constructor = ItemModule;
ItemModule.superclass = Module.prototype;

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

/**
 * Function which intializes the module.
 * @param integer id id
 * @param object element the element for the module
 */ 
ItemModule.prototype.init = function(id, element)
{
	ItemModule.superclass.init.call(this, id, element);
	
	this.storeid = false;
	this.parententryid = false;
	this.messageentryid = false;
	
	this.rootentryid = false;
	this.attachNum = false;
	
	this.attachments = new Array();
	this.newattachments = new Array();
	this.deletedattachments = new Object();
	this.owner = false;
	this.inlineattachments = new Object();
	this.inlineimages = new Array();

	// Contains all the properties for the item in this module
	this.itemProps = new Object();

}

/**
 * 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 
 */ 
ItemModule.prototype.execute = function(type, action)
{
	switch(type)
	{
		case "item":
			this.item(action);
			webclient.menu.showMenu();
			break;
	}
}

/**
 * Function which sets the properties for the item.
 * @param object action the action tag 
 */  
ItemModule.prototype.item = function(action)
{

	var message = action.getElementsByTagName("item")[0];
	this.photoLoadedFlag = false;

	if(message && message.childNodes) {

		webclient.pluginManager.triggerHook("client.module.itemmodule.item.before", {message: message});

		// remember item properties
		this.updateItemProps(message);
		
		this.setConflictInfo(message);
		this.setRecipients(message);
		var attachments = message.getElementsByTagName("attachment");
	
		if(attachments && attachments.length > 0) {
			for(var i = 0; i < attachments.length; i++)
			{
				var attach_num = attachments[i].getElementsByTagName("attach_num")[0];
				var attach_method = attachments[i].getElementsByTagName("attach_method")[0];
				var name = attachments[i].getElementsByTagName("name")[0];
				var size = attachments[i].getElementsByTagName("size")[0];
				var filetype = attachments[i].getElementsByTagName("filetype")[0];
				var hidden = attachments[i].getElementsByTagName("hidden")[0];

				// property for checking whether contactphoto is attached with attachments or not
				var attachment_contactphoto = attachments[i].getElementsByTagName("attachment_contactphoto")[0];
				// Get height width element of the photo.
				var attachment_contactphoto_sizex = attachments[i].getElementsByTagName("attachment_contactphoto_sizex")[0];
				var attachment_contactphoto_sizey = attachments[i].getElementsByTagName("attachment_contactphoto_sizey")[0];

				var cid = attachments[i].getElementsByTagName("cid")[0];
				
				
				if(attach_num && attach_num.firstChild) {
					var attachment = new Object();
					attachment["attach_num"] = attach_num.firstChild.nodeValue;
					
					if(attach_method && attach_method.firstChild) {
						attachment["attach_method"] = attach_method.firstChild.nodeValue;
					}
					
					if(name && name.firstChild) {
						attachment["name"] = name.firstChild.nodeValue;
					}
					
					if(size && size.firstChild) {
						attachment["size"] = size.firstChild.nodeValue;
					}
					
					attachment["filetype"] = (filetype && filetype.firstChild?filetype.firstChild.nodeValue:false);
					attachment["cid"] = (cid && cid.firstChild?cid.firstChild.nodeValue:false);
					attachment["hidden"] = (dhtml.getTextNode(hidden, false) == "1")?true:false;
					if (attachment_contactphoto) {
						attachment["attachment_contactphoto"] = (attachment_contactphoto.firstChild.nodeValue == "1")?true:false;
						if (attachment["attachment_contactphoto"] == true) {
							// Get height width of the photo.
							if(typeof(attachment_contactphoto_sizex) != "undefined")
								attachment["attachment_contactphoto_sizex"] = attachment_contactphoto_sizex.firstChild.nodeValue;
							if(typeof(attachment_contactphoto_sizey) != "undefined")
								attachment["attachment_contactphoto_sizey"] = attachment_contactphoto_sizey.firstChild.nodeValue;
						}
					}

					this.attachments.push(attachment);
				}
			}
		}
	
		this.setProperties(message);
		this.setAttachments(message);
		this.setBody(message);
		this.setFrom(message);

	}
	
	if(this.executeOnLoad) {
		this.executeOnLoad();
	}
}	

ItemModule.prototype.setProperties = function(message)
{
	for(var i = 0; i < message.childNodes.length; i++)
	{
		var property = message.childNodes[i];

		if(property) {
			var element = dhtml.getElementById(property.tagName);
			
			if(element) {
				// exclude "attachments" and "recipients" because we know that these are not
				// directly used as a value in the form. they are processed by 'setAttachments'
				// and 'setRecipients'.
				if (property.tagName == "attachments" || property.tagName == "recipients")
					continue;

				if(property.attributes && property.attributes.length > 0) {
					for(var j = 0; j < property.attributes.length; j++)
					{
						var item = property.attributes.item(j);
						if (item.nodeName!="type"){
							element.setAttribute(item.nodeName, item.nodeValue);
						}
					}
				}
				var value = "";
				if (property.firstChild){
					value = property.firstChild.nodeValue;
				}
				if (property.getAttribute("type") == "timestamp"){		
					value = strftime(_("%a %x %X"), property.firstChild.nodeValue);
				}
				if (value == null){
					value = "";
				}
				switch(element.tagName.toLowerCase()) 
				{
					case "span": 
					case "div": 
						element.innerHTML = value.htmlEntities();
						break; 
					default:
					case "input": 
					case "textarea": 
						element.value = value;
						break; 
				}
			}
		}
	}
} 

/**
 * setAttachmentData
 * 
 * Used by the attachment dialog to set the list of new attachments and the list of attachments that
 * have to be deleted. The dialog cannot just set it in the property of this module directly. If you
 * do this you set a reference to an Array/Object in the attachment dialog. After the user is done 
 * with uploading it will close that dialog and the reference will point to a non-existing object. 
 * There we need to create a copy of the object and remove all references. 
 * 
 * @param newattachments Array List of new attachments
 * @param deletedattachments Object List of attachments to be deleted
 */
ItemModule.prototype.setAttachmentData = function(newattachments, deletedattachments)
{
	// We have to copy the newattachments list, but cannot use the dhtml.clone function as it can not copy an Array.
	copyNewattachments = new Array();
	for(var i in newattachments){
		copyNewattachments[i] = new Object();
		for(var j in newattachments[i]){
			copyNewattachments[i][j] = newattachments[i][j];
		}
	}
	this.newattachments = copyNewattachments;

	this.deletedattachments = dhtml.clone(deletedattachments, true);
}

/**
 * Function which sets the attachments
 */ 
ItemModule.prototype.setAttachments = function()
{
	var attachmentsElement = dhtml.getElementById("itemattachments");

	if(attachmentsElement) {
		attachmentsElement.innerHTML = NBSP;
			
		// Message attachments
		this.addAttachments(attachmentsElement, this.attachments);
		// Uploaded attachments
		this.addAttachments(attachmentsElement, this.newattachments);
	
		if(attachmentsElement.innerHTML.length <= 0) {
			attachmentsElement.innerHTML = NBSP;
		}
		
		if(attachmentsElement.offsetHeight > 30) {
			attachmentsElement.style.height = "32px";
		}
	}
	resizeBody();
}

/**
 * Function which adds the attachments to the view.
 * @param object attachmentsElement element
 * @param array attachments the attachments 
 */  
ItemModule.prototype.addAttachments = function(attachmentsElement, attachments)
{
	this.setInlineAttachmentData(attachments);
	
	if(attachments && attachments.length > 0) {
		for(var i = 0; i < attachments.length; i++)
		{
			var attachment = attachments[i];

			if(attachment["attach_num"] && !attachment["hidden"]) {
				if(typeof(this.deletedattachments[attachment["attach_num"]]) == "undefined" && typeof this.inlineimages[attachments[i]["attach_num"]] == "undefined") {
					if(name && name.firstChild) {
						attachment["name"] = name.firstChild.nodeValue;
					}
					
					var kb = "0";
					if(attachment["size"]) {
						kb = Math.round(attachment["size"] / 1024) + _("kb");
						if(attachment["size"] < 1024) {
							kb = attachment["size"] + _("B");
						}
					}
					
					var attachmentElement = dhtml.addElement(attachmentsElement, "span");
					attachmentElement.setAttribute("attach_num", (attachment["attach_num"]||false));

					var attachmentLink = dhtml.addElement(attachmentElement, "a");
					attachmentLink.setAttribute("attach_num", (attachment["attach_num"]||false));
					attachmentLink.href = "#";
					var name = attachment["name"] || _("Untitled Attachment");
					attachmentLink.innerHTML = name + " (" + kb + ")";
					dhtml.addEvent(this, attachmentLink, "mousedown", eventAttachmentClick);

					dhtml.addTextNode(attachmentsElement, ";"+ NBSP);
					
					if (typeof this.inlineattachments[attachments[i]["attach_num"]] != "undefined") {
						attachmentElement.id = "inline_"+ attachments[i]["attach_num"];
					}
				}
			}

			// If contactphoto is attached then show it in photos.
			if (attachment["attachment_contactphoto"] && !this.photoLoadedFlag) {
				// push attachment into its element as Inline base64_encoded picture
				var contactphotoElement = dhtml.getElementById("contactphoto");
				var contactphotobinElement = dhtml.addElement(contactphotoElement, "img");
				contactphotobinElement.src = "index.php?load=download_attachment&store="+ this.storeid +"&entryid="+ this.messageentryid +"&attachNum[]="+ attachment["attach_num"] +"&openType=inline";

				// Set Height and width of the contact photo element.
				if(typeof(attachment["attachment_contactphoto_sizey"]) != "undefined")
					contactphotobinElement.height = attachment["attachment_contactphoto_sizey"];
				if(typeof(attachment["attachment_contactphoto_sizex"]) != "undefined")
					contactphotobinElement.width = attachment["attachment_contactphoto_sizex"];

				window.contactphotobinElement = contactphotobinElement;
				this.photoLoadedFlag = true;
			}
		}
	}
	if(!this.photoLoadedFlag) {
		var contactphotoElement = dhtml.getElementById("contactphoto");
		dhtml.addClassName(contactphotoElement,"default_contact_photo");
		this.photoLoadedFlag = true;
	}
}

/**
 * Function which sets the body
 * @param object message the action tag  
 */ 
ItemModule.prototype.setBody = function(message)
{
	var html_body = dhtml.getElementById("html_body");
	
	if(html_body) {
		var body = message.getElementsByTagName("body")[0];

		if(body && body.childNodes.length > 0) {
			var content = "";
			var element = body.firstChild;
			for(var i = 0; i < body.childNodes.length; i++)
			{
				content += element.nodeValue;
				element = element.nextSibling;
			}

			html_body.value = content;
		}
	}
}

/**
 * Function which sets the From field
 * @param object message the action tag  
 */ 
ItemModule.prototype.setFrom = function(message)
{
	var fromSelect = dhtml.getElementById("from", "select");
	
	var message_flags = parseInt(dhtml.getXMLValue(message, "message_flags", 0), 10);
	if (fromSelect && (message_flags & MSGFLAG_UNSENT)==MSGFLAG_UNSENT){

		var sent_representing_name = dhtml.getXMLValue(message, "sent_representing_name", "");
		var sent_representing_email_address = dhtml.getXMLValue(message, "sent_representing_email_address", "").toLowerCase();

		if(sent_representing_name != "" && sent_representing_email_address != ""){
			var emailString = sent_representing_name + " <" + sent_representing_email_address + ">";
			// Set the selected FROM address (only works when item is already in the list)
			fromSelect.value = emailString;
			if(fromSelect.value != emailString){
				fromSelect.options[fromSelect.options.length] = new Option(emailString);
				fromSelect.options[fromSelect.options.length-1].selected = true;
			}
			var fromRow = dhtml.getElementById("from_row", "tr");
			if(fromRow && fromSelect.options.length > 0){
				fromRow.style.display = "";
			}
		}

	}
}

/**
 * Function which sets the data for this module.
 * @param string storeid store id
 * @param string parententryid parent entry id 
 */  
ItemModule.prototype.setData = function(storeid, parententryid)
{
	if(storeid) {
		this.storeid = storeid;
	}
	
	if(parententryid) { 
		this.parententryid = parententryid;
	}
}

/**
 * Function which opens one item.
 * @param string entryid message entryid
 * @param string rootentryid the root entryid, used for embedded message in embedded message ... (optional)
 * @param array attachNum the attachment numbers, used for embedded message in embedded message ... (optional)
 */ 
ItemModule.prototype.open = function(entryid, rootentryid, attachNum)
{
	if(entryid) {
		this.messageentryid = entryid;
		
		if(rootentryid) {
			this.rootentryid = rootentryid;
		} else {
			this.rootentryid = entryid;
		}
		
		this.attachNum = attachNum;
	
		var data = new Object();
		data["store"] = this.storeid;
		data["parententryid"] = this.parententryid;
		data["entryid"] = entryid;
		
		if(rootentryid) {
			data["rootentryid"] = rootentryid;
			
			if(attachNum && attachNum.push) {
				data["attachments"] = new Object();
				data["attachments"]["attach_num"] = new Array();
				
				for(var i = 0; i < attachNum.length; i++)
				{
					data["attachments"]["attach_num"].push(attachNum[i]);
				}
			}
		}
		
		webclient.xmlrequest.addData(this, "open", data);
		webclient.xmlrequest.sendRequest();
	} else {
		webclient.menu.showMenu();
	}
}

/**
 * Function which saves an item.
 * @param object props the properties to be saved
 * @param string dialog_attachments used to add attachments (optional)   
 */ 
ItemModule.prototype.save = function(props, send, recipients, dialog_attachments)
{
	var data = new Object();
	if(this.storeid) {
		data["store"] = this.storeid;
	}
	
	if(this.parententryid)
		data["parententryid"] = this.parententryid;
		
	data["props"] = props;
	if (recipients)
		data["recipients"] = recipients;

	if (dialog_attachments)
		data["dialog_attachments"] = dialog_attachments;
	
	if(this.message_action) {
		data["message_action"] = new Object();
		data["message_action"]["action_type"] = this.message_action;
		data["message_action"]["entryid"] = this.message_action_entryid;
	}
	
	if(send) {
		data["send"] = true;
	}

	if(parentWebclient) {
		parentWebclient.xmlrequest.addData(this, "save", data, webclient.modulePrefix);
		parentWebclient.xmlrequest.sendRequest(true);
	} else {
		webclient.xmlrequest.addData(this, "save", data);
		webclient.xmlrequest.sendRequest();
	}
}

/**
 * Function which deletes an item 
 */ 
ItemModule.prototype.deleteMessage = function()
{
	if(this.messageentryid) {
		var data = new Object();
		data["store"] = this.storeid;
		data["parententryid"] = this.parententryid;
		data["entryid"] = this.messageentryid;

		/**
		 * This function is also called from main window,
		 * so need to perform typeof() check.
		 */
		if(typeof(parentWebclient) != "undefined") {
			parentWebclient.xmlrequest.addData(this, "delete", data, webclient.modulePrefix);
			parentWebclient.xmlrequest.sendRequest(true);
		} else {
			webclient.xmlrequest.addData(this, "delete", data);
			webclient.xmlrequest.sendRequest();
		}
	}
}

ItemModule.prototype.setRecipients = function(message, actionType)
{
	var sender_email_address = dhtml.getXMLValue(message, "sent_representing_email_address", "").toLowerCase();
	var sender_email_name = dhtml.getXMLValue(message, "sent_representing_name", "");
	var sender_email_address = nameAndEmailToString(sender_email_name, sender_email_address, MAPI_MAILUSER);
	
	var elemdata = new Array();

	var recipients = message.getElementsByTagName("recipient");

	if(recipients && recipients.length > 0) {
		for(var i = 0; i < recipients.length; i++)
		{
			var recipient = recipients[i];
			if(dhtml.getXMLValue(recipient, "pr_recipient_flags", false)!= 3){
				var display_name = dhtml.getXMLValue(recipient, "display_name", "");
				var email_address = dhtml.getXMLValue(recipient, "email_address", "").toLowerCase();
				var type = dhtml.getXMLValue(recipient, "type", "");
				var entryid = dhtml.getXMLValue(recipient, "entryid", "");
				var objecttype = dhtml.getXMLValue(recipient, "objecttype", "");

				if (!(actionType && actionType == "replyall" && compareEntryIds(entryid,webclient.userEntryid))){
					if(type && email_address) {
					    if(typeof(elemdata[type]) == "undefined") elemdata[type] = new Array();

                        elemdata[type].push(nameAndEmailToString(display_name,email_address,objecttype,false));
					} else if(type && display_name) {
						// if unresolved email address
						var element = dhtml.getElementById(type);
						if(element){
							elemdata[type].push(display_name);
						}
					}
				}
			}else{
				this.owner = new Object;
				this.owner["display_name"] = dhtml.getXMLValue(recipient, "display_name", false);
				this.owner["email_address"] = dhtml.getXMLValue(recipient, "email_address", false);
				this.owner["type"] = dhtml.getXMLValue(recipient, "type", false);
				this.owner["recipienttype"] = dhtml.getXMLValue(recipient, "entryid", false);
				this.owner["recipient_flags"] = dhtml.getXMLValue(recipient, "recipient_flags", 1);
			}
		}
	}
	// create a unique array of elementdata
	// this stops entering same user in type field multiple times
	for(var type in elemdata){
		//create a unique array.
		var elementArray = uniqueArray(elemdata[type]);
		if(actionType == "replyall"){
			//flag to check whether the sender is already in to field or not?
			var tosenderflag = false;
			//check if the sender is already in to field or not, if yes then make the flag true and break;
			for(var y in elemdata["to"]){
				if(elemdata["to"][y].indexOf(sender_email_address)!=-1){
					tosenderflag = true;
					break;
				}
			}
			// now check if the sender is present in to and also in cc, 
			// if yes then remove from cc field
			if(type == "cc"){
				for(var x in elementArray){
					if(elementArray[x].indexOf(sender_email_address)!=-1){
						if(!tosenderflag){
							elementArray.splice(x,1);
						}
					}
				}
			}
		}
		//re assign the values
		elemdata[type] = elementArray;
	}
	// set the data to elements.
	for(var type in elemdata) {
	    var element = dhtml.getElementById(type);
	    
	    if(element){
			element.value += elemdata[type].join("; ");
			// make unique them again, this will eliminate the duplicate contacts in to/cc feilds (if any)
			element.value = uniqueArray(element.value.split("; ")).join("; ");
		}
    }
}

/**
 * Functions to do meeting requests. These are used from various modules, including the readitemmodule, the previewreaditemmodule and the appointmentitemmodule
 * @param boolean sendResponse if it is true than reponse is sent to organizer via mail otherwise it is not sent.
 */
ItemModule.prototype.sendAcceptMeetingRequest = function(tentative, noResponse, basedate, body)
{
	// Adding human readable body text that holds the start/duedate and location information.
	body = this.addMeetingTimeInfoToBody(body, this.itemProps['startdate'], this.itemProps['duedate'], this.itemProps['location']);

	var req = new Object;
	req['entryid'] = this.messageentryid;
	req['store'] = this.storeid;
	req['tentative'] = tentative;
	req['body'] = body;

	if (typeof basedate != 'undefined' && basedate !== "false" && basedate)
		req['basedate'] = basedate;

	// if sendResponse flag is set then attach sendResponse flag with request data.
	if(typeof(noResponse) != "undefined" && noResponse)
		req['noResponse'] = noResponse;

	if(typeof parentWebclient != "undefined") {
		parentWebclient.xmlrequest.addData(this, 'acceptMeetingRequest', req, webclient.modulePrefix);
		parentWebclient.xmlrequest.sendRequest(true);
	} else {
		webclient.xmlrequest.addData(this, 'acceptMeetingRequest', req);
		webclient.xmlrequest.sendRequest(true);
	}
}
/**
 * Functions to do meeting requests. These are used from various modules, including the readitemmodule, the previewreaditemmodule and the appointmentitemmodule
 */
ItemModule.prototype.sendProposalMeetingRequest = function(start, end, body, basedate)
{
	// Adding the newly proposed time information to the body.
	body += "\n\n\n-----------\n" + _("New Meeting Time Proposed") + " :\n" +
					strftime(_("%A, %B %e, %Y %H:%M"), start) + " - " +
					strftime(_("%A, %B %e, %Y %H:%M"), end);

	var req = new Object;
	var proposalinfo = new String();
	var gmt = new String(new Date(start));
	gmt = " "+ gmt.substring(gmt.indexOf(_("GMT")));
	
	req['entryid'] = this.messageentryid;
	req['store'] = this.storeid;
	req['tentative'] = 1;
	req['proposed_starttime'] = start;
	req['proposed_endtime'] = end;
	req['proposed_duration'] = 1;
	req['counter_proposal'] = true;
	req['body'] = (body)?body:null;

	if (typeof basedate != 'undefined' && basedate)
		req['basedate'] = basedate;

	if(typeof parentWebclient != "undefined") {
		parentWebclient.xmlrequest.addData(this, 'acceptMeetingRequest', req, webclient.modulePrefix);
		parentWebclient.xmlrequest.sendRequest();
	} else {
		webclient.xmlrequest.addData(this, 'acceptMeetingRequest', req);
		webclient.xmlrequest.sendRequest();
	}
}


ItemModule.prototype.sendDeclineMeetingRequest = function(basedate, body)
{
	// Adding human readable body text that holds the start/duedate and location information.
	body = this.addMeetingTimeInfoToBody(body, this.itemProps['startdate'], this.itemProps['duedate'], this.itemProps['location']);

	var req = new Object;
	req['entryid'] = this.messageentryid;
	req['store'] = this.storeid;
	req['body'] = body;

	if (typeof basedate != 'undefined' && basedate !== "false" && basedate)
		req['basedate'] = basedate;

	if(typeof parentWebclient != "undefined") {
		parentWebclient.xmlrequest.addData(this, 'declineMeetingRequest', req, webclient.modulePrefix);
		parentWebclient.xmlrequest.sendRequest(true);
	} else {
		webclient.xmlrequest.addData(this, 'declineMeetingRequest', req);
		webclient.xmlrequest.sendRequest(true);
	}
}

/**
 * Adding human readable body text that holds the start/duedate and the location
 * of the message.
 * 
 * @param body String Body of the message
 * @param start Number Timestamp of the start date
 * @param due Number Timestamp of the due date
 * @param location String Location of the message
 */
ItemModule.prototype.addMeetingTimeInfoToBody = function(body, start, due, location){
	location = location || "";
	body = _("When") + ": " +  
					strftime(_("%A, %B %e, %Y %H:%M"), start) + " - " +
					strftime(_("%A, %B %e, %Y %H:%M"), due) + "\n" +  
					_("Where") + ": "  + location + "\n\n" + 
					"*~*~*~*~*~*~*~*~*~*\n\n" + (body||"");
	return body;
}


ItemModule.prototype.acceptMeetingRequest = function(noResponse, basedate, body)
{
	this.sendAcceptMeetingRequest(0, noResponse, basedate, body);
}

ItemModule.prototype.proposalMeetingRequest = function(start, end, body, basedate)
{
	this.sendProposalMeetingRequest(start, end, body, basedate);
}

ItemModule.prototype.tentativeMeetingRequest = function(noResponse, basedate, body)
{
	this.sendAcceptMeetingRequest(1, noResponse, basedate, body);
}

ItemModule.prototype.removeFromCalendar = function()
{
	var req = new Object;
	
	req['entryid'] = this.messageentryid;
	req['store'] = this.storeid;
	
	if(typeof parentWebclient != "undefined") {
		parentWebclient.xmlrequest.addData(this, 'removeFromCalendar', req, webclient.modulePrefix);
		parentWebclient.xmlrequest.sendRequest(true);
	} else {
		webclient.xmlrequest.addData(this, 'removeFromCalendar', req);
		webclient.xmlrequest.sendRequest();
	}
}

ItemModule.prototype.resolveConflict = function()
{
	if(typeof parentWebclient != "undefined" && parentWebclient) {
		var wc = parentWebclient;
	}else{
		var wc = webclient;
	}
	if(wc.hierarchy.isSpecialFolder('conflicts', this.itemProps["parent_entryid"])){
		if(confirm(_("You will lose the modified data. Do you want to continue?"))){
			var data = new Object();
			data["store"] = this.storeid;
			data["parententryid"] = this.parententryid;
			data["entryid"] = this.messageentryid;
			if(typeof(this.itemProps["conflictitems"]["bin"]) == "string"){
				data["conflictentryid"] = this.itemProps["conflictitems"]["bin"];
			}else{
				data["conflictentryid"] = this.itemProps["conflictitems"]["bin"][0];
			}
			wc.xmlrequest.addData(this, "resolveConflict", data, webclient.modulePrefix);
			wc.xmlrequest.sendRequest();
			dhtml.getElementById("conflict").style.display = "none";
			
			if(window.opener){
				window.opener.opener = top;
				window.opener.close()
				resizeBody();
			}
		}
	}else{
		var conflictitems = this.itemProps["conflictitems"]["bin"];
		if(typeof(conflictitems) == "string"){
			conflictitems = new Array(conflictitems);
		}
		for(var i=0;i<conflictitems.length;i++){
			if (typeof this.itemProps["message_class"] != "undefined"){
				var message_class = this.itemProps["message_class"];
			}else{
				message_class = "IPM.Note";
			}
			message_class = message_class.replace(/\./g, "_").toLowerCase();
			switch(message_class) {
				case "ipm_note":
				case "ipm_post":
				case "report_ipm_note_ndr":
				case "ipm_schedule_meeting_request":
				case "ipm_schedule_meeting_resp_pos":
				case "ipm_schedule_meeting_resp_tent":
				case "ipm_schedule_meeting_resp_neg":
				case "report_ipm_note_ipnnrn":
				case "report_ipm_note_ipnrn":
					message_class = "ipm_readmail";
					break;
			}
			if(message_class.indexOf("ipm_") >= 0) {
				message_class = message_class.substring(message_class.indexOf("_") + 1);
			}
			var uri = DIALOG_URL+"task=" + message_class + "_standard&storeid=" + this.storeid + "&entryid=" + conflictitems[i] + "&parententryid=" + this.parententryid;
			webclient.openWindow(false, message_class, uri);
		}
	}
}

ItemModule.prototype.declineMeetingRequest = function(basedate, body)
{
	this.sendDeclineMeetingRequest(basedate, body);
}

ItemModule.prototype.updateItemProps = function(item)
{
	this.itemProps = 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[prop_name] = prop_val;
			}
		}
	}
}
/**
 * Function which stores information of saved as well as new 
 * uploaded attachments.
 * @param array attachments -attachments either saved or new.
 */
ItemModule.prototype.setInlineAttachmentData = function (attachments)
{
	var dialog_attachments = dhtml.getElementById("dialog_attachments");
	if (webclient.settings.get("createmail/mailformat","html") == "html"){
		for (var i=0; i<attachments.length; i++)
		{
			var type = attachments[i]["filetype"];
			// Only for images files.
			if (type && type.substring(0, type.indexOf('/')) == "image") {
				this.inlineattachments[attachments[i]["attach_num"]] = new Object();
				this.inlineattachments[attachments[i]["attach_num"]]["name"] = attachments[i]["name"];
				this.inlineattachments[attachments[i]["attach_num"]]["cid"] = attachments[i]["cid"];
				this.inlineattachments[attachments[i]["attach_num"]]["filetype"] = attachments[i]["filetype"];
				
				if (String(attachments[i]["attach_num"]).search(/^[0-9]*$/) == -1) {
					// This is new attachment.
					this.inlineattachments[attachments[i]["attach_num"]]["path"] = BASE_URL  +"index.php?load=download_attachment&dialog_attachments="+ dialog_attachments.value +"&attachNum[]="+ attachments[i]["attach_num"];
				} else {
					if (this.messageentryid && this.storeid) {
						// This is saved attachment.
						this.inlineattachments[attachments[i]["attach_num"]]["path"] = BASE_URL +"index.php?load=download_attachment&store="+ this.storeid +"&entryid="+ this.messageentryid +"&attachNum[]="+ attachments[i]["attach_num"];
					}
				}
			}
		}
	}
}
/**
 * Function which set content id of all inline
 * images. This function is called when user
 * either saves or submits message.
 * @param object -document object of FCKeditor instance.
 */
ItemModule.prototype.setCIDInlineImages = function (editorDocument)
{
	for (var attach_Num in this.inlineimages){
		var cid = "";
		if (this.inlineattachments[attach_Num]["cid"]){
			cid = this.inlineattachments[attach_Num]["cid"];
		} else {
			cid = "image"+ generateRandomString(8) +"@"+ generateRandomString(8);
			// Save new ContectID.
			this.inlineattachments[attach_Num]["cid"] = cid;
		}
		for (var j=0; j < this.inlineimages[attach_Num]["id"].length; j++){
			var imageElement = dhtml.getElementById(this.inlineimages[attach_Num]["id"][j], "img", editorDocument);
			if (imageElement) {
				imageElement.setAttribute("_fcksavedurl","cid:"+ cid);
			}
		}
		this.inlineimages[attach_Num]["cid"] = cid;
	}
}
/**
 * Function which returns attach_Num and cid 
 * of all inline images that are either added or deleted.
 * @param object editorDocument -document object of FCKeditor instance. Required to find the images in the correct DOM tree.
 * @return array -returns array of all images used as inline. See below
 *			Array[]
 *				'add' 	 => Array[]
 *			 				 Array[0]->attach_Num
 *			 		                 ->cid
 *			 	'delete' => Array[]
 *							 Array[0]->attach_Num
 *			 		                 ->cid
 */
ItemModule.prototype.checkUsedInlineAttachments = function (editorDocument)
{
	var result = new Array();
	result["add"] = new Array();
	result["delete"] = new Array();
	
	for (var attach_Num in this.inlineimages){
		// Inline image must have a content Id.
		if (this.inlineimages[attach_Num]["cid"]){
			// Create image info to sent to server.
			var image = new Object();
			image["attach_Num"] = decodeURIComponent(attach_Num);
			image["cid"] = this.inlineimages[attach_Num]["cid"];
			var elementPresent = 0;
			
			// Check for image whether present in editor.
			for (var i in this.inlineimages[attach_Num]["id"]){
				var imageElement = dhtml.getElementById(this.inlineimages[attach_Num]["id"][i], "img", editorDocument);
				if (imageElement){
					elementPresent = 1;
					break;
				}
			}
			// If image added to editor push to add array, else if removed from editor push to delete array.
			if (elementPresent){
				result["add"].push(image);
			} else {
				result["delete"].push(image);
			}
		}
	}
	return result;
}
/**
 * Function which retrives all saved inline images
 * from the message body when body is loaded.
 * @param object editorDocument -document object of Fckeditor instance
 */
ItemModule.prototype.retrieveInlineImagesFromBody = function (editorDocument)
{
	var images = editorDocument.getElementsByTagName("img");
	for (var i=0; i<images.length; i++){
		
		var src = images[i].getAttribute("src");
		// Search for contentID and base_url.
		if (src.indexOf("attachCid=") > 0){

			var contentId = src.substr(src.indexOf("attachCid=")+10);
			contentId = contentId.substring(0, contentId.indexOf("&"));
			
			for (var attach_Num in this.inlineattachments) {
				if (contentId == this.inlineattachments[attach_Num]["cid"]){

					// Create new array object if not defined.
					if (typeof this.inlineimages[attach_Num] == "undefined"){
						this.inlineimages[attach_Num] = new Array();
						this.inlineimages[attach_Num]["id"] = new Array();
					}
					
					// Store all element ids in module variable.
					var elementId = images[i].id ? images[i].id:generateRandomString(8);
					this.inlineimages[attach_Num]["id"].push(elementId);
					this.inlineimages[attach_Num]["cid"] = contentId;
					images[i].id = elementId;
				}
			}
		}
	}
}
/**
 * Function which adds insert icon to all image attachments
 * in attachments bar.
 */
ItemModule.prototype.setAttachmentbarAttachmentOptions = function()
{
	if (typeof FCKeditorAPI != "undefined"){
		// Loop through all images of msg and add insert icon along with attachment name.
		for (var attach_num in module.inlineattachments){
			// Get element that contains attachment name.
			var attachmentElement = dhtml.getElementById("inline_"+ attach_num);
			if (attachmentElement) {
				// Check if icon is already present.
				var icon = dhtml.getElementsByClassNameInElement(attachmentElement, "icon_insert_inline", "span");
				if (icon.length == 0){
					// Add inline css class that are inline attachments
					dhtml.addClassName(attachmentElement, "inline_attachments");
					// Create insert icon and add to attachment name.
					var insertIcon = dhtml.addElement(attachmentElement, "span", "icon icon_insert_inline");
					insertIcon.title = _("Add to message body");
					// Stupid IE bug
					insertIcon.innerHTML = NBSP;
					// Set necessary events for adding image as inline to message body.
					dhtml.addEvent(module, attachmentElement, "mouseover", eventItemAttachmentNameAddInlineMouseOver);
					dhtml.addEvent(module, attachmentElement, "mouseout", eventItemAttachmentNameAddInlineMouseOut);
					dhtml.addEvent(module, insertIcon, "click", eventItemAttachmentNameAddInlineClick);
				}
			}
		}
	}
}
/**
 * Function which displays conflict information,
 * if item is in conflict state.
 *
 * @param object message message
 */
ItemModule.prototype.setConflictInfo = function (message)
{
	if (message){
		if(message.getElementsByTagName("conflictitems").length) {
			var conflict = dhtml.getElementById("conflict");
			dhtml.addEvent(this, conflict, "click", eventConflictClick);
			conflict.style.display = "block";
			if(typeof parentWebclient != "undefined" && parentWebclient) {
				var specialfolder = parentWebclient.hierarchy.isSpecialFolder('conflicts', dhtml.getXMLValue(message, "parent_entryid", ""));
			}else{
				var specialfolder = webclient.hierarchy.isSpecialFolder('conflicts', dhtml.getXMLValue(message, "parent_entryid", ""));
			}
			if(specialfolder){
				dhtml.addElement(conflict, "p", false, false, _('You made changes to another copy of this item. Click here to replace the existing item with this version.'));
			}else{
				dhtml.addElement(conflict, "p", false, false, _('You made changes to another copy of this item. This is the most recent version. Click here to see the other versions.'));
			}
			//this function adds one extra row, which spoils the layout, to fix that layout call resizeBody.
			if(typeof resizeBody != "undefined")
				resizeBody();
		}else{
		    var conflictElement = dhtml.getElementById("conflict");
		    
		    if(conflictElement)
		        conflictElement.style.display = "none";
		}
	}
}

function eventConflictClick(moduleObject, element, event)
{
	moduleObject.resolveConflict();
}

/**
 * Function which deletes out-of-date meeting request.
 */
function eventPreviewItemNotCurrentClick(moduleObject, element, event)
{
	if (confirm(_("This meeting request is out-of-date and will now be deleted."))) {
		moduleObject.deleteMessage();
		
		//Close window if meeting request is opened.
		if (typeof(parentWebclient) != "undefined"){
			window.close();
		}
	}
}
/**
 * Function which highlights attachment name on mouseover.
 */
function eventItemAttachmentNameAddInlineMouseOver(moduleObject, element, event)
{
	dhtml.addClassName(element, "attachmentover");
}
/**
 * Function which removes css class on mouseout.
 */
function eventItemAttachmentNameAddInlineMouseOut(moduleObject, element, event)
{
	dhtml.removeClassName(element, "attachmentover");
}

/**
 * Funtion which adds image to editor.
 */
function eventItemAttachmentNameAddInlineClick(moduleObject, element, event)
{
	if (typeof FCKeditorAPI != "undefined"){
		var fckEditor = FCKeditorAPI.GetInstance("html_body");
		// Get attach_num from id of parent element.
		var attach_num = element.parentNode.id.substr(element.parentNode.id.indexOf('_')+1);
		if (moduleObject.inlineattachments[attach_num]) {
			// Generate unique id for image element.
			var elementId = generateRandomString(8);
			// Create new array object if not defined.
			if (typeof moduleObject.inlineimages[attach_num] == "undefined") {
				moduleObject.inlineimages[attach_num] = new Array();
				moduleObject.inlineimages[attach_num]["id"] = new Array();
			}
			// Store all element ids in module variable.
			moduleObject.inlineimages[attach_num]["id"].push(elementId);
			// Create img tag.
			var imageElement = "<img id='"+ elementId +"' src='"+ moduleObject.inlineattachments[attach_num]["path"] +"'>";
			// Restore previous selection in editor If IE.
			if (window.BROWSER_IE)
				fckEditor.Selection.Restore();
			// Add image to editor.
			fckEditor.InsertHtml(imageElement);
			// Attachment name as it is now an inline attachment.
			element.parentNode.style.display = "none";
		}
	}
}

/**
 * Function which handles link actions to prevent termination of xmlrequests.
 */
function eventAttachmentClick(moduleObject, element, event)
{
	var attach_num = element.getAttribute("attach_num", false);
	var attachments = (moduleObject.itemProps && moduleObject.itemProps.attachments) ? moduleObject.itemProps.attachments.attachment : false;
	/**
	 * When an attachment is clicked in an edit dialog, there is also the possibility that the 
	 * attachment has not been saved at the server yet. So therefor we need add the list of unsaved 
	 * new attachments as well.
	 */
	if(!attachments && moduleObject.attachments){
		// clone array
		attachments = new Array();
		for(var i in moduleObject.attachments){
			attachments[i] = new Object();
			for(var j in moduleObject.attachments[i]){
				attachments[i][j] = moduleObject.attachments[i][j];
			}
		}

		if(moduleObject.newattachments){
			for(var i in moduleObject.newattachments){
				attachments[attachments.length] = moduleObject.newattachments[i];
			}
		}
	}

	// If only one attachment, then wrap it into an array
	if (!attachments[0]){
		attachments = new Array(attachments);
	}

	if (attach_num){
		var attachment = false;

		// Find attachment from attach_num
		for(var i = 0; i < attachments.length; i++){
			if (attachments[i]["attach_num"] === attach_num){
				attachment = attachments[i];
				break;
			}
		}

		if (attachment){
			var attachNum = "";

			if(this.attachNum && this.attachNum.push) {
				for(var j = 0; j < this.attachNum.length; j++)
				{
					attachNum += "&attachNum[]=" + this.attachNum[j];
				}
			}

			if (attachment["attach_method"] && attachment["attach_method"] == "5"){		// EMBEDDED MESSAGE
				var attach_message_class = attachment["attach_message_class"] ? attachment["attach_message_class"] : "IPM.Note";
				attach_message_class = attach_message_class.replace(/\./g, "_").toLowerCase();

				switch(attach_message_class) {
					case "ipm_note":
					case "ipm_post":
					case "report_ipm_note_ndr":
					case "ipm_schedule_meeting_request":
					case "ipm_schedule_meeting_resp_pos":
					case "ipm_schedule_meeting_resp_tent":
					case "ipm_schedule_meeting_resp_neg":
					case "ipm_schedule_meeting_canceled":
					case "report_ipm_note_ipnnrn":
					case "report_ipm_note_ipnrn":
						attach_message_class = "ipm_readmail";
						break;
				}
				if(attach_message_class.indexOf("ipm_") >= 0) {
					attach_message_class = attach_message_class.substring(attach_message_class.indexOf("_") + 1);
				}

				webclient.openWindow(false, attach_message_class, webclient.base_url + DIALOG_URL +"task="+ attach_message_class +"_standard&storeid=" + moduleObject.storeid + "&rootentryid=" + moduleObject.rootentryid + "&entryid=" + moduleObject.messageentryid + attachNum + "&attachNum[]=" + attach_num);
			} else {
				var action = webclient.base_url + "index.php?load=download_attachment&store=" + moduleObject.storeid + "&attachNum[]=" + attach_num + "&openType=attachment";
				if(moduleObject.rootentryid) {
					action += "&entryid=" + moduleObject.rootentryid;
				}

				/**
				 * When you have to open a file that is not yet saved to a message, we have to 
				 * supply the dialog_attachments identifier string. This is only present in a dialog
				 * and must be retrieved from the <INPUT id="dialog_attachments"> HTML element.
				 * This will only worki in a dialog so we have to check whether it is available or 
				 * not.
				 */
				var dialog_attachments = dhtml.getElementById("dialog_attachments");
				if(dialog_attachments && dialog_attachments.value){
					action += "&dialog_attachments="+dialog_attachments.value;
				}

				var iframe = dhtml.getElementById("iframedownload");

				if (!iframe) iframe = dhtml.addElement(document.body, "iframe", "iframeDownload", "iframedownload");
				iframe.contentWindow.location = action;
			}
		}
	}
}
