/**
 * EGroupware eTemplate2 - Countdown timer widget
 *
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
 * @package etemplate
 * @subpackage api
 * @link https://www.egroupware.org
 * @author Hadi Nategh
 */

/*egw:uses
	/vendor/bower-asset/jquery/dist/jquery.js;
	et2_core_baseWidget;
*/

import {et2_no_init} from "./et2_core_common";
import {ClassWithAttributes} from "./et2_core_inheritance";
import {et2_register_widget, WidgetConfig} from "./et2_core_widget";
import {et2_valueWidget} from "./et2_core_valueWidget";
import {egw} from "../jsapi/egw_global";

/**
 * Class which implements the "countdown" XET-Tag
 *
 * Value for countdown is an integer duration in seconds or a server-side to a duration converted expiry datetime.
 *
 * The duration has the benefit, that it does not depend on the correct set time and timezone of the browser / computer of the user.
 */
export class et2_countdown extends et2_valueWidget {
	static readonly _attributes: any = {
		format: {
			name: "display format",
			type: "string",
			default: "s", // s or l
			description: "Defines display format; s (Initial letter) or l (Complete word) display, default is s."
		},
		onFinish: {
			name: "on finish countdown",
			type: "js",
			default: et2_no_init,
			description: "Callback function to call when the countdown is finished."
		},
		hideEmpties: {
			name: "hide empties",
			type: "string",
			default: true,
			description: "Only displays none empty values."
		},
		precision: {
			name: "how many counters to show",
			type: "integer",
			default: 0,	// =all
			description: "Limit number of counters, eg. 2 does not show minutes and seconds, if days are displayed"
		},
		alarm: {
			name: "alarm",
			type: "any",
			default: "",
			description: "Defines an alarm set before the countdown is finished, it should be in seconds"
		},
		onAlarm: {
			name: "alarm callback",
			type: "js",
			default: "",
			description: "Defines a callback to gets called at alarm - timer. This only will work if there's an alarm set."
		}
	};

	private time : Date;

	private timer = null;
	private container : JQuery = null;
	private days : JQuery = null;
	private hours : JQuery = null;
	private minutes : JQuery = null;
	private seconds : JQuery = null;

	/**
	 * Constructor
	 */
	constructor(_parent, _attrs?: WidgetConfig, _child?: object) {
		// Call the inherited constructor
		super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_countdown._attributes, _child || {}));

		// Build countdown dom container
		this.container = jQuery(document.createElement("div"))
			.addClass("et2_countdown");
		this.days = jQuery(document.createElement("span"))
			.addClass("et2_countdown_days").appendTo(this.container);
		this.hours = jQuery(document.createElement("span"))
			.addClass("et2_countdown_hours").appendTo(this.container);
		this.minutes = jQuery(document.createElement("span"))
			.addClass("et2_countdown_minutes").appendTo(this.container);
		this.seconds = jQuery(document.createElement("span"))
			.addClass("et2_countdown_seconds").appendTo(this.container);
		this.setDOMNode(this.container[0]);
	}

	public set_value(_time)
	{
		if (isNaN(_time)) return;

		super.set_value(_time);

		if(this.timer)
		{
			clearInterval(this.timer);
		}

		this.time = new Date();
		this.time.setSeconds(this.time.getSeconds() + parseInt(_time));

		let self = this;
		this.timer = setInterval(function(){
			if (self._updateTimer() <= 0)
			{
				clearInterval(self.timer);
				if (typeof self.onFinish == "function") self.onFinish();
			}
		}, 1000);
	}

	private _updateTimer()
	{
		let now = new Date();
		let distance = this.time.getTime() - now.getTime();

		if (distance < 0) return 0;

		let alarms = [];
		if (Array.isArray(this.options.alarm))
		{
			alarms = this.options.alarm;
		}
		else
		{
			alarms[this.options.alarm] = this.options.alarm;
		}

		// alarm values should be set as array index to reduce its time complexity from O(n) to O(1)
		// otherwise the execution time might be more than a second which would cause timer being delayed
		if (alarms[Math.floor(distance/1000)] && typeof this.onAlarm == 'function')
		{
			this.egw().debug("log", 'alarm is called')
			this.onAlarm();
		}

		let values = {
			days: Math.floor(distance / (1000 * 60 * 60 * 24)),
			hours: Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
			minutes: Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)),
			secounds: Math.floor((distance % (1000 * 60)) / 1000)
		};

		this.days.text(values.days+this._getIndicator("days"));
		this.hours.text(values.hours+this._getIndicator("hours"))
		this.minutes.text(values.minutes+this._getIndicator("minutes"));
		this.seconds.text(values.secounds+this._getIndicator("seconds"));

		if (this.options.hideEmpties)
		{
			if (values.days == 0)
			{
				this.days.hide();
				if(values.hours == 0)
				{
					this.hours.hide();
					if(values.minutes == 0)
					{
						this.minutes.hide();
						if(values.secounds == 0) this.seconds.hide();
					}
				}
			}
		}
		if (this.options.precision)
		{
			const units = ['days','hours','minutes','seconds'];
			for (let u=0; u < 4; ++u)
			{
				if (values[units[u]])
				{
					for(let n=u+this.options.precision; n < 4; n++)
					{
						this[units[n]].hide();
					}
					break;
				}
				else
				{
					this[units[u]].hide();
				}
			}
		}
		return distance;
	}

	private _getIndicator(_v)
	{
		return this.options.format == 's' ? egw.lang(_v).substr(0,1) : egw.lang(_v);
	}
}
et2_register_widget(et2_countdown, ["countdown"]);
