/**
 * EGroupware - Timesheet - Javascript UI
 *
 * @link http://www.egroupware.org
 * @package timesheet
 * @author Hadi Nategh	<hn-AT-stylite.de>
 * @copyright (c) 2008-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
 */

/*egw:uses
	/api/js/jsapi/egw_app.js
 */
import '../../api/js/jsapi/egw_global';

import {EgwApp} from '../../api/js/jsapi/egw_app';
import {egw} from "../../api/js/jsapi/egw_global";
import {Et2DateTimeReadonly} from "../../api/js/etemplate/Et2Date/Et2DateTimeReadonly";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
import {Et2DateTime} from "../../api/js/etemplate/Et2Date/Et2DateTime";
import {et2_grid} from "../../api/js/etemplate/et2_widget_grid";
import type {Et2ButtonToggle} from "../../api/js/etemplate/Et2Button/Et2ButtonToggle";
import type {Et2Select} from "../../api/js/etemplate/Et2Select/Et2Select";

/**
 * UI for timesheet
 *
 * @augments AppJS
 */
class TimesheetApp extends EgwApp
{

	// These fields help with push filtering & access control to see if we care about a push message
	protected push_grant_fields = ["ts_owner"];
	protected push_filter_fields = ["ts_owner"]

	constructor()
	{
		super('timesheet');
	}

	/**
	 * This function is called when the etemplate2 object is loaded
	 * and ready.  If you must store a reference to the et2 object,
	 * make sure to clean it up in destroy().
	 *
	 * @param et2 etemplate2 Newly ready object
	 * @param string name
	 */
	et2_ready(et2, name: string)
	{
		// call parent
		super.et2_ready(et2, name);

		if (name == 'timesheet.index')
		{
			this.filter_change();
			this.filter2_change();
		}
	}

	/**
	 * Enable or disable the date filter
	 *
	 * If the filter is set to something that needs dates, we open the
	 * filter-box and show start- and endtime.
	 *
	 * @param ev
	 * @param filter
	 */
	filter_change(ev : Event, filter : Et2Select)
	{
		const dates = this.et2.getWidgetById('timesheet.index.dates');
		if (filter && dates)
		{
			dates.set_disabled(filter.value !== "custom");
			if (!filter.value) this.nm.activeFilters.startdate = null;
			if (filter.value === "custom")
			{
				const filterDrawer = filter.closest('egw-app').filtersDrawer;
				if (filterDrawer && !filterDrawer.open)
				{
					filterDrawer.open = true;
				}
				window.setTimeout(() => dates.getWidgetById('startdate').focus());
			}
		}
		return true;
	}

	/**
	 * show or hide the details of rows by selecting the filter2 option
	 * either 'all' for details or 'no_description' for no details
	 *
	 * @param ev
	 * @param filter2
	 */
	filter2_change(ev : Event, filter2 : Et2Select)
	{
		if (this.nm && filter2)
		{
			egw.css("#timesheet-index span.timesheet_titleDetails","font-weight:" + (filter2.getValue() == '1' ? "bold;" : "normal;"));
			// Show / hide descriptions
			egw.css(".ts_description", "display:" + (filter2.value == '1' ? "flex;" : "none;"));
		}
	}

	/**
	 * Wrapper so add action in the context menu can pass current
	 * filter values into new edit dialog
	 *
	 * @see add_with_extras
	 *
	 * @param {egwAction} action
	 * @param {egwActionObject[]} selected
	 */
	add_action_handler(action, selected)
	{
		var nm = action.getManager().data.nextmatch || false;
		if(nm)
		{
			this.add_with_extras(nm);
		}
	}

	/**
	 * Opens a new edit dialog with some extra url parameters pulled from
	 * nextmatch filters.
	 *
	 * @param {et2_widget} widget Originating/calling widget
	 */
	add_with_extras(widget)
	{
		var nm = widget.getRoot().getWidgetById('nm');
		var nm_value = nm.getValue() || {};

		var extras : any = {};
		if (nm_value.cat_id)
		{
			extras.cat_id = nm_value.cat_id;
		}

		if (nm_value.col_filter && nm_value.col_filter.linked)
		{
			if(typeof nm_value.col_filter.linked === "string")
			{
				const split = nm_value.col_filter.linked.split(':') || '';
				extras.link_app = split[0] || '';
				extras.link_id = split[1] || '';
			}
			else
			{
				extras.link_app = nm_value.col_filter.linked.app;
				extras.link_id = nm_value.col_filter.linked.id;
			}
		}
		if (nm_value.col_filter && nm_value.col_filter.pm_id)
		{
			extras.link_app = 'projectmanager';
			extras.link_id = nm_value.col_filter.pm_id;
		}
		else if (nm_value.col_filter && nm_value.col_filter.ts_project)
		{
			extras.ts_project = nm_value.col_filter.ts_project;
		}

		egw.open('','timesheet','add',extras);
	}

	/**
	 * Change handler for project selection to set empty ts_project string, if project get deleted
	 *
	 * @param {type} _egw
	 * @param {et2_widget_link_entry} _widget
	 * @returns {undefined}
	 */
	pm_id_changed(_egw, _widget)
	{
		// Update price list
		var ts_pricelist = _widget.getRoot().getWidgetById('pl_id');
		egw.json('projectmanager_widget::ajax_get_pricelist',[_widget.getValue()],function(value) {
			ts_pricelist.set_select_options(value||{})
		}).sendRequest(true);

		var ts_project = this.et2.getWidgetById('ts_project');
		if (ts_project)
		{
			ts_project.set_blur(_widget.getValue() ? _widget.search.val() : '');
		}
	}

	/**
	 * Update custom filter timespan, without triggering a change
	 */
	update_timespan(start, end)
	{
		if(this && this.et2)
		{
			var nm = this.et2.getWidgetById('nm');
			if(nm)
			{
				// Toggle update_in_progress to avoid another request
				nm.update_in_progress = true;
				this.et2.getWidgetById('startdate').set_value(start);
				this.et2.getWidgetById('enddate').set_value(end);
				nm.activeFilters.startdate = start;
				nm.activeFilters.enddate = end;
				nm.update_in_progress = false;
			}
		}
	}

	/**
	 * If editing a timesheet and no quantity is set, update the placeholder text when duration changes
	 *
	 * This is for display only
	 */
	update_quantity(event, widget)
	{
		const quantity = this.et2.getWidgetById("ts_quantity");
		if(quantity)
		{
			// use decimal separator from user prefs
			const format = this.egw.preference('number_format');
			const sep = format ? format[0] : '.';

			// Duration is in minutes, round to hours with 2 decimals
			const minutes = parseInt(widget.value) / 60;
			let val = "" + Math.round((minutes + Number.EPSILON) * 1000) / 1000;
			if(format && sep && sep !== '.')
			{
				val = val.replace('.', sep);
			}

			// Clear actual value to update if it was nearly the same
			const old_val = parseInt(widget._oldValue) / 60;
			if(Math.abs(quantity.valueAsNumber - old_val) < 0.01)
			{
				quantity.value = "";
			}

			// Set placeholder
			quantity.placeholder = val;
		}
	}

	/**
	 * Get title in order to set it as document title
	 * @returns {string}
	 */
	getWindowTitle()
	{
		return this.et2.getValueById('ts_title');
	}

	/**
	 * Run action via ajax
	 *
	 * @param _action
	 * @param _senders
	 */
	ajax_action(_action, _senders)
	{
		let all = _action.parent.data.nextmatch?.getSelection().all;
		let ids = [];
		for(let i = 0; i < _senders.length; i++)
		{
			ids.push(_senders[i].id.split("::").pop());
		}
		egw.json("timesheet.timesheet_ui.ajax_action",[_action.id, ids, all]).sendRequest(true);
	}

	/**
	 * Edit time of an event in events tab of edit timesheet
	 *
	 * @param MouseEvent _ev
	 * @param Et2DateTimeReadonly _widget
	 */
	editEventTime(_ev : MouseEvent, _widget : Et2DateTimeReadonly)
	{
		_ev.stopPropagation();	// tab-panel somehow also gets the event
		if (this.et2.getInstanceManager().isDirty())
		{
			Et2Dialog.alert(this.egw.lang('You have unsaved changes, you need save them before editing events!'), this.egw.lang('Unsaved changes'));
			return;
		}
		const tse_id = _widget.closest('tr')?.id?.replace('timesheet-events::', '');
		const grid = <et2_grid>_widget.getParent();
		const tse_type = parseInt(grid.getWidgetById(_widget.id.replace('[tse_time]', '[tse_type]')).value[0]);
		const dialog = new Et2Dialog(this.egw);
		dialog.getUpdateComplete().then(() =>
		{
			const time = <Et2DateTime><any>dialog.eTemplate.widgetContainer.getWidgetById('time');
			// start-time set end-time as max
			if (0+tse_type & 1)
			{
				time.set_max((<Et2DateTimeReadonly><any>grid.getWidgetById(_widget.id.replace(/^(\d+)/,
					n => (parseInt(n)+1).toString()))).value);
			}
			// stop- or pause-time, set start-time as min
			else
			{
				time.set_min((<Et2DateTimeReadonly><any>grid.getWidgetById(_widget.id.replace(/^(\d+)/,
					n => (parseInt(n)-1).toString()))).value);
			}
		});
		// Set attributes.  They can be set in any way, but this is convenient.
		dialog.transformAttributes({
			callback: (_button, _values) => {
				const change = (new Date(_widget.value)).valueOf() - (new Date(_values.time)).valueOf();
				if (_button === Et2Dialog.OK_BUTTON && change)
				{
					_widget.value = _values.time;
					egw.request('timesheet.EGroupware\\Timesheet\\Events.ajax_updateTime',
						[tse_id, new Date((new Date(_values.time)).valueOf() + egw.getTimezoneOffset() * 60000)])
						.then(_data =>
						{
							// reload the whole dialog
							window.location.href = window.location.href+'&tabs=events';
						});
				}
			},
			title: egw.lang('Change time'),
			template: 'timesheet.edit.events.change',
			buttons: Et2Dialog.BUTTONS_OK_CANCEL,
			value: {
				content: { time: _widget.value }
			}
		});
		// Add to DOM, dialog will auto-open
		document.body.appendChild(dialog);
	}

	/**
	 * Show details has been clicked
	 */
	toggleDetails(_ev : Event, _widget : Et2ButtonToggle)
	{
		this.nm && this.nm.applyFilters({filter2: _widget.value ? '1' : ''});
	}

	/**
	 * Check if any NM filter or search in app-toolbar needs to be updated to reflect NM internal state
	 *
	 * @param app_toolbar
	 * @param id
	 * @param value
	 */
	checkNmFilterChanged(app_toolbar, id : string, value : string)
	{
		super.checkNmFilterChanged(app_toolbar, id, value);

		if (id === 'filter2')
		{
			const details_toggle = this.et2.getWidgetById('details');
			if (details_toggle && details_toggle.value != (value === '1')) {
				details_toggle.value = value === '1';
			}
			// if it's a real change, we also need to call this.filter2_change, with the already changed value!
			const filter2 = this.et2.getWidgetById(id);
			if (filter2 && filter2.value != value)
			{
				filter2.value = value;
				this.filter2_change(null, filter2);
			}
		}
		else if (id === 'filter')
		{
			this.filter_change(null, this.et2.getWidgetById(id));
		}
	}
}

app.classes.timesheet = TimesheetApp;