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

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);
	this.events["row"]["dblclick"] = eventAppointmentListDblClickMessage;
	delete this.events["row"]["mousedown"];

	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.initializeView();

}

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);
	this.contentElement = dhtml.addElement(this.element, "div", false, "calendar");

	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;
		}
	}

	this.viewController.initView(this.id, this.selectedview, this.contentElement, this.events, data);
	
	// 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;
	}
}

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();
		data["restriction"]["startdate"] = this.startdate / 1000;
		data["restriction"]["duedate"] = this.duedate / 1000;
	
		webclient.xmlrequest.addData(this, "list", data);
		this.viewController.loadMessage();
	}
}

appointmentlistmodule.prototype.getAppointmentProps = function(starttime, endtime, subject, location, label, busystatus, remindertime)
{
	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"] = "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)
{
	this.save(this.getAppointmentProps(starttime, endtime, subject, location, label, busystatus, remindertime));
}

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;
	}
}

// Called when delete button in menu is pressed
appointmentlistmodule.prototype.deleteMessages = function ()
{
	this.deleteAppointments(this.getSelectedMessages(), true);
}

// Actually delete a single series or an occurrence of a series
appointmentlistmodule.prototype.deleteAppointment = function(entryid, basedate)
{
	if(basedate) {
		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 {
		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)
{
	var itemEl = dhtml.getElementById(messages[0]);

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

	var selected = this.getSelectedMessages();
	var selectedElement = dhtml.getElementById(selected[0]);
	var basedate = itemEl.attributes["basedate"] ? itemEl.attributes["basedate"].value : false;
	var meeting = 0;
	var send = false;

	if(itemEl.attributes["basedate"]) { // any item with a basedate is recurring
		if(promptoccurrence) {
			if(selectedElement.meetingrequest && Number(selectedElement.meetingrequest)==1) {
				meeting = selectedElement.meetingrequest;
				// calculated end date of appointment to check whether the update to attendees is send or not, for different views of calendar. 
				var end = (selectedElement.end)? selectedElement.end: selectedElement.getAttribute("duedate"); 
				var endtime = new Date(end * 1000);
				if(endtime.getTime() > (new Date().getTime())) {
					send = confirm(_("Would you like to send an update to the attendees regarding changes to this meeting?"));
				}
			}

			// 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+"&send="+send, 300, 200);
		} else {
			// shortcut directly to deleteAppointment if prompting for occurrence/series deletion is off
			this.deleteAppointment(entryid, basedate);
		}
	}else{
		// do a normal delete
		var meetingrequestResponseStatusOrganizer = (selectedElement.meetingrequest && Number(selectedElement.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 = (selectedElement.end)? selectedElement.end: selectedElement.getAttribute("duedate"); 
			var endtime = new Date(end * 1000);
			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) {
			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 {
			// Use superclass deleteMessages to actually delete the items
			appointmentlistmodule.superclass.deleteMessages.call(this, messages);
		}
	}
}

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 eventAppointmentListDblClickMessage(moduleObject, element, event)
{
	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 {
		// added parameter to increase width of appointment standard dialogbox to accomadate the german translation 
		var uri = DIALOG_URL+"task=appointment_standard&storeid=" + moduleObject.storeid + "&parententryid=" + moduleObject.entryid + "&entryid=" + moduleObject.entryids[element.id] + "&parententryid=" + moduleObject.entryid;
		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(this);
}

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;
}
