/*
 * 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/>.
 * 
 */

appointmentlistmodule.prototype = new ListModule;
appointmentlistmodule.prototype.constructor = appointmentlistmodule;
appointmentlistmodule.superclass = ListModule.prototype;

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

appointmentlistmodule.prototype.init = function(id, element, title, data)
{
	this.entryid = data["entryid"];
	this.selectedview = webclient.settings.get("folders/entryid_"+this.entryid+"/selected_view", "workweek");
	
	this.startdate = false;
	this.duedate = false;

	this.setDays(new Date().getTime());
	
	data["has_no_menu"] = true;
	appointmentlistmodule.superclass.init.call(this, id, element, title, data);
	
	//Generate the condition to initialize mousedown event and set readflag on double click in table view
	if(this.selectedview != "table"){
		delete this.events["row"]["mousedown"];
		this.events["row"]["dblclick"] = eventAppointmentListDblClickMessage;	
	}
	
	var items = new Array();
	items.push(webclient.menu.createMenuItem("open", _("Open"), false, eventAppointmentListContextMenuOpenMessage));
	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, eventAppointmentListContextMenuDeleteMessage));
	this.contextmenu = items;
	this.keys["view"] = KEYS["view"];

	this.initializeView();
	// Used by keycontrol, to switch between views
	this.availableViews = new Array("day", "workweek", "week", "7days", "month", "table");
}

appointmentlistmodule.prototype.initializeView = function(view)
{
	if (view){
		this.selectedview = view;
		webclient.settings.set("folders/entryid_"+this.entryid+"/selected_view", view);
	}
	this.setTitle(this.title, false, true);
	//check for the divelement's height in table view so that scroll bar is perfectly visible. 
	if(this.selectedview != "table")
		this.contentElement = dhtml.addElement(this.element, "div", false, "calendar")
	else
		this.contentElement = dhtml.addElement(this.element, "div");
	// this event allows to select a row while we click on an item in list 
		this.events["row"]["mousedown"] = eventListMouseDownMessage;
	
	var data = new Object();
	data["startdate"] = this.startdate;
	data["duedate"] = this.duedate;
	data["selecteddate"] = this.selectedDate;

	// Set onDrop Event
	if(typeof(dragdrop) != "undefined") {
		switch(this.selectedview){
			case "day":	
			case "7days":
			case "workweek":	
				dragdrop.setOnDropGroup("appointment", this.id, eventAppointmentListDragDropTarget);
				break;
			case "week":
				dragdrop.setOnDropGroup("appointment", this.id, eventCalenderWeekViewDragDropTarget);
				break;
			case "month":		
				dragdrop.setOnDropGroup("appointment", this.id, eventCalenderMonthViewDragDropTarget);
				break;	
			case "table":
				dragdrop.setOnDropGroup("folder", this.id, eventListDragDropTarget);
				break;
		}
	}

	this.viewController.initView(this.id, this.selectedview, this.contentElement, this.events, data);
	
	// Add keycontrol events
	webclient.inputmanager.addObject(this, this.element);
	if (!webclient.inputmanager.hasKeyControlEvent(this, "keyup", eventAppointmentListKeyCtrlChangeView)){
		webclient.inputmanager.bindKeyControlEvent(this, this.keys["view"], "keyup", eventAppointmentListKeyCtrlChangeView);
	}
	webclient.inputmanager.bindKeyControlEvent(this, this.keys["refresh"], "keyup", eventListKeyCtrlRefreshFolder);
	
	// Resize the cells
	this.resize();
}

/**
 * getDragDropTargetCallback
 * 
 * This function returns the correct event function to handle the dragdrop event. 
 * In this case we use the legacy system in the dragdrop widget with the 
 * dragdrop.setOnDropGroup() method in the initializeView method.
 * 
 * @return function|boolean dragdrop even function or false if none
 */
appointmentlistmodule.prototype.getDragDropTargetCallback = function(){
	return false;
}

/**
 * Function which updates the view with the given timestamp. This function is called in
 * the date picker module. 
 */ 
appointmentlistmodule.prototype.changeDays = function(timestamp)
{
	if (timestamp) {
		this.setDays(timestamp);
	}
	
	var data = new Object();
	data["startdate"] = this.startdate;
	data["duedate"] = this.duedate;
	data["selecteddate"] = this.selectedDate; 

	this.viewController.viewObject.setData(data);

	this.list();
	
}

/**
 * Function which calculates the start and enddate.
 */ 
appointmentlistmodule.prototype.setDays = function(timestamp)
{
	var timestampdate = new Date(timestamp);
		
	var date = new Date();
	date.setTimeStamp(timestampdate.getDate(), timestampdate.getMonth()+1, timestampdate.getFullYear()); 

	this.selectedDate = date;
	
	// TODO: check DST
	switch(this.selectedview)
	{
		case "day":
			this.startdate = date.getTime();
			this.duedate = date.getTime() + ONE_DAY;
			break;
		case "workweek":
			var weekday = date.getDay();
			if (weekday==0) weekday = 7;
			this.startdate = date.getTime() - ((weekday - 1) * ONE_DAY);
			this.duedate = date.getTime() + ((6 - weekday) * ONE_DAY);
			break;
		case "7days":
			var weekday = date.getDay();
			if (weekday==0) weekday = 7;
			this.startdate = date.getTime() - ((weekday - 1) * ONE_DAY);
			this.duedate = date.getTime() + ((8 - weekday) * ONE_DAY);
			break;
		case "week":
			var weekday = date.getDay();
			if (weekday==0) weekday = 7;
			this.startdate = date.getTime() - ((weekday - 1) * ONE_DAY);
			this.duedate = date.getTime() + ((8 - weekday) * ONE_DAY);
			break;
		case "month":
			var month_start = new Date(date.getTime());
			month_start.setDate(1);
			var month_end = new Date(date.getTime());
			month_end.setDate(date.getDaysInMonth());
			this.startdate = month_start.getTime() - (6 * ONE_DAY);
			this.duedate = month_end.getTime() + (14 * ONE_DAY);
			break;
		// this will set start and end date for list view 
   		// as there is no restriction on start and end date it is set false
		case "table":
			this.startdate = false;
			this.duedate = false;
			break;	
	}
}

appointmentlistmodule.prototype.list = function(useTimeOut)
{
	if(this.storeid && this.entryid) {
		var data = new Object();
		data["store"] = this.storeid;
		data["entryid"] = this.entryid;
		data["restriction"] = new Object();
		//this is to set restriction on start and end date if it is false
		data["restriction"]["startdate"] = (this.startdate && this.duedate) ? this.startdate/1000 : 0;
		data["restriction"]["duedate"] =  (this.startdate && this.duedate) ? this.duedate/1000 : 0 ;
		
		webclient.xmlrequest.addData(this, "list", data);
		this.viewController.loadMessage();
	}
	//called superclass list method to set restriction for sorting and paging
	appointmentlistmodule.superclass.list.call(this, useTimeOut);
}

appointmentlistmodule.prototype.getAppointmentProps = function(starttime, endtime, subject, location, label, busystatus, remindertime, alldayevent)
{
	var props = new Object();
	props["store"] = this.storeid;
	props["parent_entryid"] = this.entryid;
	props["message_class"] = "IPM.Appointment";
	if(subject)
		props["subject"] = subject;

	if(location)
		props["location"] = location;

	if(label)
		props["label"] = label;
	else
		props["label"] = 0;

	if(busystatus)
		props["busystatus"] = busystatus;
	else
		props["busystatus"] = 2;

	props["startdate"] = starttime;
	props["commonstart"] = starttime;

	props["duedate"] = endtime;	
	props["commonend"] = endtime;

	props["duration"] = (endtime-starttime)/60;
	props["alldayevent"] = (alldayevent)?1:"false";
	
	props["reminder"] = "false";
	props["reminder_minutes"] = 15;
	if(remindertime && remindertime > 0) {
		props["reminder"] = "true";
		props["reminder_minutes"] = remindertime;
	}

	props["reminder_time"] = starttime;
	props["flagdueby"] = starttime - props["reminder_minutes"];

	props["icon_index"] = 1024;
	props["importance"] = 1;
	props["sensitivity"] = 0;
	props["private"] = -1;
	props["responsestatus"] = 0;
	props["meeting"] = 0;

	props["recurring"] = "false";
	props["commonassign"] = 0;
	
	return props;
}

appointmentlistmodule.prototype.createAppointment = function(starttime, endtime, subject, location, label, busystatus, remindertime, alldayevent)
{
	this.save(this.getAppointmentProps(starttime, endtime, subject, location, label, busystatus, remindertime, alldayevent));
}

appointmentlistmodule.prototype.destructor = function()
{
	dhtml.removeEvent(document.body, "mouseup", eventListCheckSelectedContextMessage);
	dragdrop.deleteGroup("appointment");
	appointmentlistmodule.superclass.destructor(this);
}

appointmentlistmodule.prototype.changeView = function (type,timestamp)
{
	switch (type){
		case "workweek":
			this.datepicker.changeView("workweek", false);
			this.datepicker.changeSelectedDate(timestamp, true);
			break;
		case "day":
			this.datepicker.changeView("day", false);
			this.datepicker.changeSelectedDate(timestamp, true);
			break;
		case "week":
			this.datepicker.changeView("week", false);
			this.datepicker.changeSelectedDate(timestamp, true);
			break;
		case "table":
			this.datepicker.changeView("table", false);
			break;	
	}
}

// Called when delete button in menu is pressed
appointmentlistmodule.prototype.deleteMessages = function (selecteMessages, softDelete)
{
	// for Shift + Del, passed softDelete value.
	this.deleteAppointments(this.getSelectedMessages(), true, softDelete);
}

// Actually delete a single series or an occurrence of a series
appointmentlistmodule.prototype.deleteAppointment = function(entryid, basedate, elementId)
{
	var selectedElement = dhtml.getElementById(elementId);
	var send = false;

	if(basedate) {
		//occurrence end date
		var end = (selectedElement.end)? selectedElement.end: (selectedElement.getAttribute("end"))? selectedElement.getAttribute("end"): selectedElement.getAttribute("duedate");
		var endtime = new Date(end * 1000);

		// if occurrence is later then send confirmation message for cancellation message.
		if(selectedElement.meetingrequest && parseInt(selectedElement.meetingrequest, 10) == 1) {
			if(endtime.getTime() > (new Date().getTime()))
				send = confirm(_("Would you like to send an update to the attendees regarding changes to this meeting?"));
		}
		if(send) {
			// delete occurrence and send cancellation message
			var data = new Array();
			data["store"] = this.storeid;
			data["entryid"] = entryid;
			data["delete"] = true;
			data["exception"] = true;
			data["basedate"] = basedate;
			
			// The cancel call will delete the meeting appointment for us
			webclient.xmlrequest.addData(this, "cancelInvitation", data, webclient.modulePrefix);
			webclient.xmlrequest.sendRequest(true);
		} else {
			//directlly delete passed occurrence.
			var req = new Object;
			req['store'] = this.storeid;
			req['parententryid'] = this.entryid;
			req['entryid'] = entryid;
			req['delete'] = 1;
			req['props'] = new Object;
			req['props']['entryid'] = entryid;
			req['props']['basedate'] = parseInt(basedate, 10);
			webclient.xmlrequest.addData(this, 'save', req, webclient.modulePrefix);
		}
	} else {
		// Recurrence end date
		var end = this.itemProps[entryid].enddate_recurring;
		var endtime = new Date(end * 1000);

		// if recurrence is later then send confirmation message for cancellation message.
		if(selectedElement.meetingrequest && parseInt(selectedElement.meetingrequest, 10) == 1) {
			if(endtime.getTime() > (new Date().getTime()))
				send = confirm(_("Would you like to send an update to the attendees regarding changes to this meeting?"));
		}
		if(send) {
			// delete MR and send cancellation message
			var data = new Array();
			data["store"] = this.storeid;
			data["entryid"] = entryid;

			// The cancel call will delete the item for us
			webclient.xmlrequest.addData(this, "cancelInvitation", data);
			webclient.xmlrequest.sendRequest(true);
		} else {
			//directlly delete passed MRs.
			appointmentlistmodule.superclass.deleteMessage.call(this, entryid);
		}
	}
}

// This is the main DELETE function. It is called from the context menu, when pressing 'del' and when pressing the
// delete button in the menu. It asks you any special handling question before proceeding to the actual delete
// Quirk: only prompts for the first entry to be deleted, but deletes all the messages passed in 'messages'
appointmentlistmodule.prototype.deleteAppointments = function(messages, promptoccurrence, softDelete)
{
	var itemEl = false;
	/**
	 * if messages is an array (in case of multiday appointment), we need 
	 * to check that the element on which delete action is fired, is 
	 * exists in DOM or not, if yes then which element exists. ( case, 
	 * when appointment starts on sunday and ends on monday, so we can hv
	 * only one element view at a time.)
	 */
	for(var elIndex = 0; elIndex < messages.length; elIndex++){
		if(dhtml.getElementById(messages[elIndex])){
			itemEl = dhtml.getElementById(messages[elIndex]);
			break;
		}
	}

	if(!itemEl) return;

	var messageClass = false;
	var classNames = itemEl.className.split(" ");
	var entryid = this.entryids[itemEl.id];

	var basedate = itemEl.attributes["basedate"] ? itemEl.attributes["basedate"].value : false;
	var meeting = 0;
	var send = false;
	var deleteMessage = true;

	if(basedate) { // any item with a basedate is recurring
		if(promptoccurrence) {
			// open dialog for question if the series must be deleted or just the occurrence
			webclient.openModalDialog(this, "deleteoccurrence", DIALOG_URL+"entryid="+entryid+"&storeid="+this.storeid+"&task=deleteoccurrence_modal&basedate="+basedate+"&parententryid="+this.entryid+"&meeting="+meeting+"&elementid="+itemEl.id, 300, 200, null, null, {parentModule: this});
		} else {
			// shortcut directly to deleteAppointment if prompting for occurrence/series deletion is off
			this.deleteAppointment(entryid, basedate, itemEl.id);
		}
	}else{
		// do a normal delete
		var meetingrequestResponseStatusOrganizer = (itemEl.meetingrequest && Number(itemEl.meetingrequest)==1);
		if (meetingrequestResponseStatusOrganizer) { // 1 = olResponseOrganized
			// calculated end date of appointment to check whether the update to attendees is send or not, for different views of calendar. 
			var end = (itemEl.end)? itemEl.end: itemEl.getAttribute("duedate"); 
			var endtime = new Date(end * 1000);
			if( endtime.getTime()>(new Date().getTime())){
				// don't ask for meeting requests which are occuring in past
				send = confirm(_("Would you like to send an update to the attendees regarding changes to this meeting?"));
				deleteMessage = false;
			}
		}

		if(send) {
			var data = new Array();
			data["store"] = this.storeid;
			data["entryid"] = entryid;

			// The cancel call will delete the item for us	
			webclient.xmlrequest.addData(this, "cancelInvitation", data);
		} else if (deleteMessage) {
			// Use superclass deleteMessages to actually delete the items
			appointmentlistmodule.superclass.deleteMessages.call(this, messages, softDelete);
		}
	}
}


appointmentlistmodule.prototype.handleActionFailure = function(action)
{
	var move = false;

	switch(dhtml.getXMLValue(action, "action_type", "none")){
		case "moveoccurence":
			var errorMessageString = dhtml.getXMLValue(action, "error_message");
			if(errorMessageString != false)
				alert(errorMessageString);
			break;
	}
}

/**
 * Function to get the multiday appointments elements reference.
 * @param String elementId String which represents the Elements Id.
 * @return Array result Array of elements which should get selected.
 */
appointmentlistmodule.prototype.getMultiDayItemInObject = function(elementId){
	var elemObjEntryIds = new Array(elementId);
	if(this.viewController.viewObject.itemElementLookup && typeof this.viewController.viewObject.itemElementLookup[this.entryids[elementId]] != "undefined"){
		elemObjEntryIds = this.viewController.viewObject.itemElementLookup[this.entryids[elementId]];
	}
	return elemObjEntryIds;
}

/**
 * Function to open a dialog box to create an appointment or meeting request.
 * @param String elementId String which represents the Elements Id.
 * @return Array result Array of elements which should get selected.
 */
appointmentlistmodule.prototype.openCreateAppointmentDialog = function(type, allDayFlag, element){
	var startEndTimeFromSelection = this.viewController.viewObject.getStartEndTimeOfSelection(true, element);
	var uri = 	DIALOG_URL+
				"storeid=" + this.storeid + 
				"&parententryid=" + this.entryid;
	if(startEndTimeFromSelection){
		var starttime = startEndTimeFromSelection[0];
		var endtime = startEndTimeFromSelection[1];
		
		uri += 	"&startdate=" + starttime +
				"&enddate=" + endtime ;
		uri += (type) ?"&meeting=true":"";
	}else{
		uri += 	"&entryid=" + this.entryids[this.getSelectedMessages()];
	}
	if(allDayFlag){
		uri += 	"&allDayEvent=true";
	}
	var el = dhtml.getElementById(this.getSelectedMessages());
	var basedate = (el && (typeof el.getAttribute("basedate") != "undefined" || el.getAttribute("basedate") != null))?el.getAttribute("basedate") : false;
	if(basedate) { // any item with a basedate is recurring
		uri += "&task=occurrence_standard&basedate=" + basedate;
		webclient.openWindow(this, "occurrence", uri, 300, 200);
	} else {
		uri += "&task=appointment_standard";
		webclient.openWindow(this, "appointment", uri);
	}
}

function eventAppointmentListDblClickMessage(moduleObject, element, event)
{
	event.stopPropagation();
	var messageClass = false;
	var classNames = element.className.split(" ");
	
	var entryid = moduleObject.entryids[element.id];

	if(element.getAttribute("basedate")) { // any item with a basedate is recurring
		basedate = element.attributes["basedate"].value;

		// please note that this url is also printed, so make it more "interesting" by first set the entryid
		webclient.openWindow(moduleObject, "occurrence", DIALOG_URL+"entryid="+entryid+"&storeid="+moduleObject.storeid+"&task=occurrence_standard&basedate="+basedate+"&parententryid="+moduleObject.entryid, 300, 200);
	} else {
		var uri = DIALOG_URL+"task=appointment_standard&storeid=" + moduleObject.storeid + "&parententryid=" + moduleObject.entryid + "&entryid=" + entryid + "&parententryid=" + moduleObject.entryid;
		// added parameter to increase width of appointment standard dialogbox to accomadate the german translation 
		webclient.openWindow(moduleObject, messageClass, uri, 860, 560);
	}
}

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

	var itemEl = dhtml.getElementById(element.parentNode.elementid);

	var messageClass = false;
	var classNames = itemEl.className.split(" ");
	var entryid = moduleObject.entryids[itemEl.id];

	if(itemEl.getAttribute("basedate")) { // any item with a basedate is recurring
		var basedate = itemEl.attributes["basedate"].value;
		// please note that this url is also printed, so make it more "interesting" by first set the entryid
		webclient.openWindow(moduleObject, "occurrence", DIALOG_URL+"entryid="+entryid+"&storeid="+moduleObject.storeid+"&task=occurrence_standard&basedate="+basedate+"&parententryid="+moduleObject.entryid, 300, 200);
	} else {
		var uri = DIALOG_URL+"task=appointment_standard&storeid=" + moduleObject.storeid + "&parententryid=" + moduleObject.entryid + "&entryid=" + entryid;
		webclient.openWindow(moduleObject, messageClass, uri);
	}

	eventListCheckSelectedContextMessage(moduleObject);
}

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

	moduleObject.deleteAppointments(moduleObject.getSelectedMessages(element.parentNode.elementid), true); // don't prompt for occurrence

	eventListCheckSelectedContextMessage(moduleObject);
}
/**
 * Keycontrol function which switches to next/previous view
 */
function eventAppointmentListKeyCtrlChangeView(moduleObject, element, event)
{
	var newView = false;

	// Select previous view
	if (event.keyCombination == this.keys["view"]["prev"]){
		newView = array_prev(moduleObject.selectedview, moduleObject.availableViews);
	} else if (event.keyCombination == this.keys["view"]["next"]){
		// Select next view
		newView = array_next(moduleObject.selectedview, moduleObject.availableViews);
	}

	if (newView){
		moduleObject.datepicker.changeView(newView, true);
	}
}

function confirmAppointMoved(moduleObject, currentDay, targetDay)
{
	if(currentDay != targetDay){
		if(!confirm(_("You changed the date of this occurence. If you want to change the date of all occurences, you must first open the appointment series. Do you want to change only this occurence?"))){
			/**
			 * Here position of the occurrence is changed,
			 * so replace it with original call list function of module.
			 */
			moduleObject.list();
			return false;
		}
	}
	return true;
}

/**
 * Event function for showing context menu for creating appointments.
 * @param object moduleObject Contains all the properties of a module object.
 * @param dom_element element The dom element's reference on which the event gets fired.
 * @param event event Event name
 */
function eventShowCreateAppointmentContextMenu(moduleObject, element, event){
	var items = new Array();
	var elem = element;
	items.push(webclient.menu.createMenuItem("appointment", _("Create Appointment"), _("Create Appointment"), function(){eventCalendarContextMenuClickCreateAppointment(moduleObject, elem, event)}));
	items.push(webclient.menu.createMenuItem("meetingrequest", _("Create Meetingrequest"), _("Create Meetingrequest"), function(){eventCalendarContextMenuClickCreateAppointment(moduleObject, elem, event, "meeting")}));
	webclient.menu.buildContextMenu(moduleObject, element.id, items, event.clientX, event.clientY);
}

/**
 * event for opening a dialog box for creating of appointments
 * @param object moduleObject Contains all the properties of a module object.
 * @param dom_element element The dom element's reference on which the event gets fired.
 * @param event event Event name
 * @param type type Event whether meeting request or empty for appointment
 */
function eventCalendarContextMenuClickCreateAppointment(moduleObject, element, event, type){
	if(dhtml.getElementById("contextmenu")){
		dhtml.getElementById("contextmenu").style.display = "none";
	}
	moduleObject.openCreateAppointmentDialog(type, true, element);
}
