'use strict';
'require view';
'require rpc';
'require ui';
'require uci';
'require fs';

var pkg = {
	get Name() { return 'luci-app-advanced-reboot'; },
	get URL() { return 'https://docs.openwrt.melmac.net/' + pkg.Name + '/'; }
};

return view.extend({
	translateTable: {
		NO_BOARD_NAME : function(args) { return _('Unable to find Device Board Name.')},
		NO_DUAL_FLAG: function (args) { return _('Unable to find Dual Boot Flag Partition.') },
		NO_DUAL_FLAG_BLOCK: function (args) { return _('The Dual Boot Flag Partition: %s is not a block device.').format(args[0])},
		ERR_SET_DUAL_FLAG : function(args) { return _('Unable to set Dual Boot Flag Partition entry for partition: %s.').format(args[0])},
		NO_FIRM_ENV : function(args) { return _('Unable to obtain firmware environment variable: %s.').format(args[0])},
		ERR_SET_ENV : function(args) { return _('Unable to set firmware environment variable: %s to %s.').format(args[0],args[1])}
	},

	callReboot: rpc.declare({
		object: 'system',
		method: 'reboot',
		expect: { result: 0 }
	}),

	callObtainDeviceInfo: rpc.declare({
		object: 'luci.advanced_reboot',
		method: 'obtain_device_info',
		expect: {  }
	}),

	callTogglePartition: rpc.declare({
		object: 'luci.advanced_reboot',
		method: 'toggle_boot_partition',
		expect: {  }
	}),

	callPowerOff: function() {
		return fs.exec('/sbin/poweroff').then(function() {
			ui.showModal(_('Shutting down...'), [
				E('p', { 'class': 'spinning' }, _('The system is shutting down now.<br /> DO NOT POWER OFF THE DEVICE!<br /> It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
			]);
		})
	},

	handlePowerOff: function() {

		ui.showModal(_('Power Off Device'), [
			E('p', _("WARNING: Power off might result in a reboot on a device which doesn't support power off.<br /><br />\
			Click \"Proceed\" below to power off your device.")),
			E('div', { 'class': 'right' }, [
				E('button', {
					'class': 'btn',
					'click': ui.hideModal
				}, _('Cancel')), ' ',
				E('button', {
					'class': 'btn cbi-button cbi-button-positive important',
					'click': L.bind(this.callPowerOff, this)
				}, _('Proceed'))
			])
		]);

	},

	handleReboot: function(ev) {
		return this.callReboot().then(function(res) {
			if (res != 0) {
				ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
				L.raise('Error', 'Reboot failed');
			}

			ui.showModal(_('Rebooting…'), [
				E('p', { 'class': 'spinning' }, _('Waiting for device...'))
			]);

			window.setTimeout(function() {
				ui.showModal(_('Rebooting…'), [
					E('p', { 'class': 'spinning alert-message warning' },
						_('Device unreachable! Still waiting for device...'))
				]);
			}, 150000);

			ui.awaitReconnect();
		})
		.catch(function(e) { ui.addNotification(null, E('p', e.message)) });
	},

	handleTogglePartition: function(ev) {
		return this.callTogglePartition().then(L.bind(function(res) {
			if (res.error) {
				ui.hideModal()
				return ui.addNotification(null, E('p', this.translateTable[res.error](res.args)));
			}

			return this.callReboot().then(function(res) {
				if (res != 0) {
					ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
					L.raise('Error', 'Reboot failed');
				}

				ui.showModal(_('Rebooting…'), [
					E('p', { 'class': 'spinning' }, _('The system is rebooting to an alternative partition now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
				]);

				window.setTimeout(function() {
					ui.showModal(_('Rebooting…'), [
						E('p', { 'class': 'spinning alert-message warning' },
							_('Device unreachable! Still waiting for device...'))
					]);
				}, 150000);

				ui.awaitReconnect();
			})
			.catch(function(e) { ui.addNotification(null, E('p', e.message)) });
		}, this));
	},

	handleAlternativeReboot: function(ev) {
		return Promise.all([
			L.resolveDefault(fs.stat('/usr/sbin/fw_printenv'), null),
			L.resolveDefault(fs.stat('/usr/sbin/fw_setenv'), null),
		]).then(L.bind(function (data) {
			if (!data[0] || !data[1]) {
				return ui.addNotification(null, E('p', _('No access to fw_printenv or fw_printenv!')));
			}

			ui.showModal(_('Reboot Device to an Alternative Partition') + " - " + _("Confirm"), [
				E('p', _("WARNING: An alternative partition might have its own settings and completely different firmware.<br /><br />\
				As your network configuration and WiFi SSID/password on alternative partition might be different,\
					you might have to adjust your computer settings to be able to access your device once it reboots.<br /><br />\
				Please also be aware that alternative partition firmware might not provide an easy way to switch active partition\
					and boot back to the currently active partition.<br /><br />\
				Click \"Proceed\" below to reboot device to an alternative partition.")),
				E('div', { 'class': 'right' }, [
					E('button', {
						'class': 'btn',
						'click': ui.hideModal
					}, _('Cancel')), ' ',
					E('button', {
						'class': 'btn cbi-button cbi-button-positive important',
						'click': L.bind(this.handleTogglePartition, this)
					}, _('Proceed'))
				])
			]);
		}, this))
	},

	parsePartitions: function(partitions) {
		var res = [];

		partitions.forEach(L.bind(function(partition) {
			var func, text;

			if (partition.state == 'Current') {
				func = 'handleReboot';
				text = _('Reboot to current partition');
			} else {
				func = 'handleAlternativeReboot';
				text = _('Reboot to alternative partition...');
			}

			res.push([
				(partition.number+0x100).toString(16).substr(-2).toUpperCase(),
				_(partition.state),
				partition.os.replace("Unknown", _("Unknown")).replace("Compressed", _("Compressed")),
				E('button', {
					'class': 'btn cbi-button cbi-button-apply important',
					'click': ui.createHandlerFn(this, func)
				}, text)
			])
		}, this));

		return res;
	},

	load: function() {
		return Promise.all([
			uci.changes(),
			L.resolveDefault(fs.stat('/sbin/poweroff'), null),
			this.callObtainDeviceInfo()
		]);
	},

	render: function(data) {
		var changes = data[0],
			poweroff_supported = data[1] != null ? true : false,
			device_info = data[2];

		var body = E([
			E('h2', _('Advanced Reboot'))
		]);

		for (var config in (changes || {})) {
			body.appendChild(E('p', { 'class': 'alert-message warning' },
				_('Warning: There are unsaved changes that will get lost on reboot!')));
			break;
		}

		if (device_info.error)
			body.appendChild(E('p', { 'class' : 'alert-message warning'}, _("ERROR: ") + this.translateTable[device_info.error]()));

		body.appendChild(E('h3', (device_info.device_name || '') + _(' Partitions')));
		if (device_info.device_name) {
			var partitions_table = E('table', { 'class': 'table' }, [
				E('tr', { 'class': 'tr table-titles' }, [
					E('th', { 'class': 'th' }, [ _('Partition') ]),
					E('th', { 'class': 'th' }, [ _('Status') ]),
					E('th', { 'class': 'th' }, [ _('Firmware') ]),
					E('th', { 'class': 'th' }, [ _('Reboot') ])
				])
			]);

			cbi_update_table(partitions_table, this.parsePartitions(device_info.partitions));

			body.appendChild(partitions_table);
		} else {
			body.appendChild(E('p', { 'class' : 'alert-message warning'},
			device_info.rom_board_name ? _("Warning: Device (%s) is unknown or isn't a dual-firmware device!" + "%s" +
					"If you are seeing this on an OpenWrt dual-firmware supported device," + "%s" + "please refer to " +
					"%sHow to add a new device section of the README%s.").format(device_info.rom_board_name, "<br /><br />", "<br />",
						"<a href=\"" + pkg.URL + "#how-to-add-a-new-device\" target=\"_blank\">", "</a>" )
				: _('Warning: Unable to obtain device information!')
			));

		}

		body.appendChild(E('hr'));
		body.appendChild(
			poweroff_supported ? E('button', {
				'class': 'btn cbi-button cbi-button-apply important',
				'click': ui.createHandlerFn(this, 'handlePowerOff')
			}, _('Perform power off...'))

			: E('p', { 'class' : 'alert-message warning'},
			_('Warning: This system does not support powering off!'))
		);

		return body;
	},

	handleSaveApply: null,
	handleSave: null,
	handleReset: null
});
