'use strict';
'require uci';
'require rpc';
'require fs';
'require form';
'require tools.widgets as widgets';

var callGetLogServices, callInitAction, callDDnsGetStatus;

var NextUpdateStrings = {};

NextUpdateStrings = {
	'Verify' : _("Verify"),
	'Run once' : _("Run once"),
	'Disabled' : _("Disabled"),
	'Stopped' : _("Stopped")
}

var time_res = {};
time_res['seconds'] = 1;
time_res['minutes'] = 60;
time_res['hours'] = 3600;

callGetLogServices = rpc.declare({
	object: 'luci.ddns',
	method: 'get_services_log',
	params: [ 'service_name' ],
	expect: {  },
});

callInitAction = rpc.declare({
	object: 'luci',
	method: 'setInitAction',
	params: [ 'name', 'action' ],
	expect: { result: false }
});

callDDnsGetStatus = rpc.declare({
	object: 'luci.ddns',
	method: 'get_ddns_state',
	expect: {  }
});

return L.view.extend({

	callDDnsGetEnv: rpc.declare({
		object: 'luci.ddns',
		method: 'get_env',
		expect: {  }
	}),

	callDDnsGetServicesStatus: rpc.declare({
		object: 'luci.ddns',
		method: 'get_services_status',
		expect: {  }
	}),

	poll_status: function(map, data) {
		var status = data[1] || [], service = data[0] || [], rows = map.querySelectorAll('.cbi-section-table-row[data-sid]'),
			section_id, cfg_detail_ip, cfg_update, cfg_status, host, ip, last_update,
			next_update, service_status, reload, cfg_enabled, stop,
			ddns_enabled = map.querySelector('[data-name="_enabled"]').querySelector('.cbi-value-field'),
			ddns_toggle = map.querySelector('[data-name="_toggle"]').querySelector('button');

		ddns_toggle.innerHTML = status['_enabled'] ? _('Stop DDNS') : _('Start DDNS')

		L.dom.content(ddns_enabled, function() {
			return E([], [
				E('div', {}, status['_enabled'] ? _('DDNS Autostart enabled') : [
					_('DDNS Autostart disabled'),
					E('div', { 'class' : 'cbi-value-description' },
					_("Currently DDNS updates are not started at boot or on interface events.") + "<br>" +
					_("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')"))
				]),]);
		});

		for (var i = 0; i < rows.length; i++) {
			section_id = rows[i].getAttribute('data-sid');
			cfg_detail_ip = rows[i].querySelector('[data-name="_cfg_detail_ip"]');
			cfg_update = rows[i].querySelector('[data-name="_cfg_update"]');
			cfg_status = rows[i].querySelector('[data-name="_cfg_status"]');
			reload = rows[i].querySelector('.cbi-section-actions .reload');
			stop = rows[i].querySelector('.cbi-section-actions .stop');
			cfg_enabled = uci.get('ddns', section_id, 'enabled');

			reload.disabled = (status['_enabled'] == 0 || cfg_enabled == 0);

			host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error');
			ip =  _('No Data');
			last_update = _('Never');
			next_update = _('Unknown');
			service_status = '<b>' + _('Not Running') + '</b>';

			if (service[section_id]) {
				stop.disabled = (!service[section_id].pid || (service[section_id].pid && cfg_enabled == '1'));
				if (service[section_id].ip)
					ip = service[section_id].ip;
				if (service[section_id].last_update)
					last_update = service[section_id].last_update;
				if (service[section_id].next_update)
					next_update = NextUpdateStrings[service[section_id].next_update] || service[section_id].next_update;
				if (service[section_id].pid)
					service_status = '<b>' + _('Running') + '</b> : ' + service[section_id].pid;
			}

			cfg_detail_ip.innerHTML = host + '<br>' + ip;
			cfg_update.innerHTML = last_update + '<br>' + next_update;
			cfg_status.innerHTML = service_status;
		}

		return;
	},

	load: function() {
		return Promise.all([
			this.callDDnsGetServicesStatus(),
			callDDnsGetStatus(),
			this.callDDnsGetEnv(),
			fs.lines('/etc/ddns/services'),
			fs.lines('/etc/ddns/services_ipv6'),
			uci.load('ddns')
		]);
	},

	render: function(data) {
		var resolved = data[0] || [];
		var status = data[1] || [];
		var env = data[2] || [];
		var logdir = uci.get('ddns', 'global', 'ddns_logdir') || "/var/log/ddns";

		var services4 = [];
		var services6 = [];

		data[3].forEach(function(item) {
			if (!item.startsWith("#")) {
				services4.push(item.split('\t')[0].slice(1,-1));
			}
		});

		data[4].forEach(function(item) {
			if (!item.startsWith("#")) {
				services6.push(item.split('\t')[0].slice(1,-1));
			}
		});

		var m, s, o;

		m = new form.Map('ddns', _('Dynamic DNS'));

		var is = m.section(form.NamedSection, 'global', 'ddns', _('Information'));

		s = is;

		o = s.option(form.DummyValue, '_version', _('Dynamic DNS Version'));
		o.cfgvalue = function() {
			return status[this.option];
		};

		o = s.option(form.DummyValue, '_enabled', _('State'));
		o.cfgvalue = function() {
			var res = status[this.option];
			if (!res) {
				this.description = _("Currently DDNS updates are not started at boot or on interface events.") + "<br>" +
				_("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')")
			}
			return res ? _('DDNS Autostart enabled') : _('DDNS Autostart disabled')
		};

		o = s.option(form.DummyValue, '_toggle', '&nbsp');
		o.cfgvalue = function() {
			var action = status['_enabled'] ? 'stop' : 'start';
			return E([], [
				E('button', {
				'class': 'cbi-button cbi-button-apply',
				'click': L.ui.createHandlerFn(this, function() {
					return callDDnsGetStatus().then(L.bind(function(data) {
						return callInitAction('ddns', action == 'stop' ? 'disable' : 'enable').then(function() {
							return callInitAction('ddns', action);
						});
					}, this)).then(L.bind(m.render, m));
				})
			}, _(action.toUpperCase() + ' DDns'))]);
		};

		o = s.option(form.DummyValue, '_restart', '&nbsp');
		o.cfgvalue = function() {
			return E([], [
				E('button', {
				'class': 'cbi-button cbi-button-apply',
				'click': L.ui.createHandlerFn(this, function() {
					return callInitAction('ddns', 'restart').then(L.bind(m.render, m));
				})
			}, _('Restart DDns'))]);
		};

		// DDns hints

		if (!env['has_ipv6']) {
			o = s.option(form.DummyValue, '_no_ipv6');
			o.rawhtml  = true;
			o.title = '<b>' + _("IPv6 not supported") + '</b>';
			o.cfgvalue = function() { return _("IPv6 is currently not (fully) supported by this system") + "<br>" +
			_("Please follow the instructions on OpenWrt's homepage to enable IPv6 support") + "<br>" +
			_("or update your system to the latest OpenWrt Release")};
		}

		if (!env['has_ssl']) {
			o = s.option(form.DummyValue, '_no_https');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("HTTPS not supported") + '</b>';
			o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to support secure updates via HTTPS protocol.") +
			"<br />- " +
			_("You should install 'wget' or 'curl' or 'uclient-fetch' with 'libustream-*ssl' package.") +
			"<br />- " +
			_("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
		}

		if (!env['has_bindnet']) {
			o = s.option(form.DummyValue, '_no_bind_network');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("Binding to a specific network not supported") + '</b>';
			o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") +
			"<br />- " +
			_("You should install 'wget' or 'curl' package.") +
			"<br />- " +
			_("GNU Wget will use the IP of given network, cURL will use the physical interface.") +
			"<br />- " +
			_("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
		}

		if (!env['has_proxy']) {
			o = s.option(form.DummyValue, '_no_proxy');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("cURL without Proxy Support") + '</b>';
			o.cfgvalue = function() { return _("cURL is installed, but libcurl was compiled without proxy support.") +
			"<br />- " +
			_("You should install 'wget' or 'uclient-fetch' package or replace libcurl.") +
			"<br />- " +
			_("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
		}

		if (!env['has_forceip']) {
			o = s.option(form.DummyValue, '_no_force_ip');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("Force IP Version not supported") + '</b>';
			o.cfgvalue = function() { return _("BusyBox's nslookup and Wget do not support to specify " +
				"the IP version to use for communication with DDNS Provider!") +
				"<br />- " + _("You should install 'wget' or 'curl' or 'uclient-fetch' package.")
			};
		}

		if (!env['has_bindhost']) {
			o = s.option(form.DummyValue, '_no_dnstcp');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("DNS requests via TCP not supported") + '</b>';
			o.cfgvalue = function() { return _("BusyBox's nslookup and hostip do not support to specify to use TCP " +
				"instead of default UDP when requesting DNS server!") +
				"<br />- " +
				_("You should install 'bind-host' or 'knot-host' or 'drill' package for DNS requests.")};
		}

		if (!env['has_dnsserver']) {
			o = s.option(form.DummyValue, '_no_dnsserver');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("Using specific DNS Server not supported") + '</b>';
			o.cfgvalue = function() { return _("BusyBox's nslookup in the current compiled version " +
			"does not handle given DNS Servers correctly!") +
		"<br />- " +
		_("You should install 'bind-host' or 'knot-host' or 'drill' or 'hostip' package, " +
			"if you need to specify a DNS server to detect your registered IP.")};
		}

		if (env['has_ssl'] && !env['has_cacerts']) {
			o = s.option(form.DummyValue, '_no_certs');
			o.titleref = L.url("admin", "system", "opkg")
			o.rawhtml  = true;
			o.title = '<b>' + _("No certificates found") + '</b>';
			o.cfgvalue = function() { return _("If using secure communication you should verify server certificates!") +
			"<br />- " +
			_("Install 'ca-certificates' package or needed certificates " +
				"by hand into /etc/ssl/certs default directory")};
		}

		// DDns services
		s = m.section(form.GridSection, 'service', _('Services'));
		s.anonymous = true;
		s.addremove = true;
		s.addbtntitle = _('Add new services...');

		s.anonymous = true;
		s.addremove = true;
		s.sortable  = true;

		s.handleAdd = function(ev) {
			var m2 = new form.Map('ddns'),
				s2 = m2.section(form.NamedSection, '_new_');

			s2.render = function() {
				return Promise.all([
					{},
					this.renderUCISection('_new_')
				]).then(this.renderContents.bind(this));
			};

			name = s2.option(form.Value, 'name', _('Name'));
			name.rmempty = false;
			name.datatype = 'uciname';
			name.placeholder = _('New DDns Service…');
			name.validate = function(section_id, value) {
				if (uci.get('ddns', value) != null)
					return _('The service name is already used');

				return true;
			};

			m2.render().then(L.bind(function(nodes) {
				L.ui.showModal(_('Add new services...'), [
					nodes,
					E('div', { 'class': 'right' }, [
						E('button', {
							'class': 'btn',
							'click': L.ui.hideModal
						}, _('Cancel')), ' ',
						E('button', {
							'class': 'cbi-button cbi-button-positive important',
							'click': L.ui.createHandlerFn(this, function(ev) {
								var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null;

								if (nameval == null || nameval == '')
									return;

								return m.save(function() {
									uci.add('ddns', 'service', nameval);
								}).then(L.bind(m.children[1].renderMoreOptionsModal, m.children[1], nameval));
							})
						}, _('Create service'))
					])
				], 'cbi-modal');

				nodes.querySelector('[id="%s"] input[type="text"]'.format(name.cbid('_new_'))).focus();
			}, this));
		};

		s.renderRowActions = function(section_id) {
			var tdEl = this.super('renderRowActions', [ section_id, _('Edit') ]),
				cfg_enabled = uci.get('ddns', section_id, 'enabled'),
				reload_opt = {
					'class': 'cbi-button cbi-button-neutral reload',
					'click': L.ui.createHandlerFn(this, function() {
						return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
							[ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
					}),
					'title': _('Reload this service'),
				},
				stop_opt = {
					'class': 'cbi-button cbi-button-neutral stop',
					'click': L.ui.createHandlerFn(this, function() {
						return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
							[ '-S', section_id, '--', 'start' ]).then(L.bind(m.render, m));
					}),
					'title': _('Stop this service'),
				};

			if (status['_enabled'] == 0 || cfg_enabled == 0)
				reload_opt['disabled'] = 'disabled';

			if (!resolved[section_id] || !resolved[section_id].pid ||
					(resolved[section_id].pid && cfg_enabled == '1'))
				stop_opt['disabled'] = 'disabled';

			L.dom.content(tdEl.lastChild, [
				E('button', stop_opt, _('Stop')),
				E('button', reload_opt, _('Reload')),
				tdEl.lastChild.childNodes[0],
				tdEl.lastChild.childNodes[1],
				tdEl.lastChild.childNodes[2]
			]);

			return tdEl;
		};

		o = s.option(form.DummyValue, '_cfg_name', _('Name'));
		o.modalonly = false;
		o.textvalue = function(section_id) {
			return '<b>' + section_id + '</b>';
		}

		o = s.option(form.DummyValue, '_cfg_detail_ip', _('Lookup Hostname') + "<br>" + _('Registered IP'));
		o.rawhtml   = true;
		o.modalonly = false;
		o.textvalue = function(section_id) {
			var host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'),
				ip = _('No Data');
			if (resolved[section_id] && resolved[section_id].ip)
				ip = resolved[section_id].ip;

			return host + '<br>' + ip;
		};

		o = s.option(form.Flag, 'enabled', _('Enabled'));
		o.rmempty  = false;
		o.editable = true;
		o.modalonly = false;

		o = s.option(form.DummyValue, '_cfg_update', _('Last Update') + "<br>" + _('Next Update'));
		o.rawhtml   = true;
		o.modalonly = false;
		o.textvalue = function(section_id) {
			var last_update = _('Never'), next_update = _('Unknown');
			if (resolved[section_id]) {
				if (resolved[section_id].last_update)
					last_update = resolved[section_id].last_update;
				if (resolved[section_id].next_update)
					next_update =  NextUpdateStrings[resolved[section_id].next_update] || resolved[section_id].next_update;
			}

			return  last_update + '<br>' + next_update;
		};

		s.modaltitle = function(section_id) {
			return _('DDns Service') + ' » ' + section_id;
		};

		o = s.option(form.DummyValue, '_cfg_status', _('Status'));
		o.modalonly = false;
		o.textvalue = function(section_id) {
			var text = '<b>' + _('Not Running') + '</b>';

			if (resolved[section_id] && resolved[section_id].pid)
				text = '<b>' + _('Running') + '</b> : ' + resolved[section_id].pid;

			return text;
		}


		s.tab('basic', _('Basic Settings'));
		s.tab('advanced', _('Advanced Settings'));
		s.tab('timer', _('Timer Settings'));
		s.tab('logview', _('Log File Viewer'));

		// TAB: BASIC

		// enabled
		o = s.taboption('basic', form.Flag, 'enabled', _('Enabled'),_("If this service section is disabled it could not be started." + "<br />" +
		"Neither from LuCI interface nor from console"));
		o.modalonly = true;
		o.rmempty  = false;
		o.default = '1';

		// lookup_host

		o = s.taboption('basic', form.Value, 'lookup_host', _("Lookup Hostname"),
		_("Hostname/FQDN to validate, if IP update happen or necessary") );
		o.rmempty	= false;
		o.placeholder = "myhost.example.com";
		o.datatype = 'and(minlength(3),hostname("strict"))';
		o.modalonly = true;

		// use_ipv6

		o = s.taboption('basic', form.ListValue, 'use_ipv6', _("IP address version"),
		_("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider"));
		o.default = '0';
		o.modalonly = true;
		o.rmempty  = false;

		o.value("0", _("IPv4-Address"))
		if (env["has_ipv6"])
			o.value("1", _("IPv6-Address"))

		// service_name

		o = s.taboption('basic', form.ListValue, 'ipv4_service_name', _("DDNS Service provider") + " [IPv4]");
		o.depends("use_ipv6", "0")
		o.modalonly = true;

		for (var i = 0; i < services4.length; i++)
			o.value(services4[i]);

		o.value('-',"-- " + _("custom") + " --");

		o.cfgvalue = function(section_id) {
			return uci.get('ddns', section_id, 'service_name');
		}

		o.write = function(section_id, formvalue) {
			if (formvalue != '-') {
				uci.set('ddns', section_id, 'update_url', null);
				uci.set('ddns', section_id, 'update_script', null);
				return uci.set('ddns', section_id, 'service_name', formvalue);
			}
			return uci.set('ddns', section_id, 'service_name', null);
		};

		o = s.taboption('basic', form.ListValue, 'ipv6_service_name', _("DDNS Service provider") + " [IPv6]");
		o.depends("use_ipv6", "1")
		o.modalonly = true;

		for (var i = 0; i < services6.length; i++)
			o.value(services6[i]);

			o.value('-',"-- " + _("custom") + " --");

		o.cfgvalue = function(section_id) {
			return uci.get('ddns', section_id, 'service_name');
		}

		o.write = function(section_id, formvalue) {
			if (formvalue != '-') {
				uci.set('ddns', section_id, 'update_url', null);
				uci.set('ddns', section_id, 'update_script', null);
				return uci.set('ddns', section_id, 'service_name', formvalue);
			}
			return uci.set('ddns', section_id, 'service_name', null);
		};

		// update_url

		o = s.taboption('basic', form.Value, 'update_url', _("Custom update-URL"),
		_("Update URL to be used for updating your DDNS Provider." + "<br />" +
		"Follow instructions you will find on their WEB page."));
		o.modalonly = true;
		o.rmempty	= false;
		o.depends("ipv6_service_name","-");
		o.depends("ipv4_service_name","-");

		// update_script

		o = s.taboption('basic', form.Value, 'update_script', _("Custom update-script"),
		_("Custom update script to be used for updating your DDNS Provider."));
		o.modalonly = true;
		o.rmempty	= false;
		o.depends("ipv6_service_name","-");
		o.depends("ipv4_service_name","-");

		// domain

		o = s.taboption('basic', form.Value, 'domain', _("Domain"),
		_("Replaces [USERNAME] in Update-URL (URL-encoded)"));
		o.modalonly = true;
		o.rmempty	= false;

		// username

		o = s.taboption('basic', form.Value, 'username', _("Username"),
		_("Replaces [USERNAME] in Update-URL (URL-encoded)"));
		o.modalonly = true;
		o.rmempty	= false;

		// password


		o = s.taboption('basic', form.Value, 'password', _("Password"),
		_("Replaces [PASSWORD] in Update-URL (URL-encoded)"));
		o.password = true;
		o.modalonly = true;
		o.rmempty	= false;

		// param_enc

		o = s.taboption('basic', form.Value, 'param_enc', _("Optional Encoded Parameter"),
		_("Optional: Replaces [PARAMENC] in Update-URL (URL-encoded)"));
		o.optional = true;
		o.modalonly = true;

		// param_opt

		o = s.taboption('basic', form.Value, 'param_opt', _("Optional Parameter"),
		_("Optional: Replaces [PARAMOPT] in Update-URL (NOT URL-encoded)"));
		o.optional = true;
		o.modalonly = true;

		// use_https

		if (env['has_ssl']) {
			o = s.taboption('basic', form.Flag, 'use_https', _("Use HTTP Secure"),
				_("Enable secure communication with DDNS provider"));
			o.optional = true;
			o.modalonly = true;

			o = s.taboption('basic', form.Value, 'cacert',
				_("Path to CA-Certificate"),
				_("directory or path/file") + "<br>" +
				_("or") + '<b>' + " IGNORE " + '</b>' +
				_("to run HTTPS without verification of server certificates (insecure)"));
			o.modalonly = true;
			o.depends("use_https", "1");
			o.placeholder = "/etc/ssl/certs";
			o.rmempty	= false;
		};

		// TAB Advanced

		// ip_source

		o = s.taboption('advanced', form.ListValue, 'ip_source', _("IP address source"),
		_("Defines the source to read systems IP-Address from, that will be send to the DDNS provider"));

		o.modalonly = true;
		o.default = "network";
		o.value("network", _("Network"));
		o.value("web", _("URL"));
		o.value("interface", _("Interface"));
		o.value("script", _("Script"));

		o.write = function(section_id, formvalue) {
			switch(formvalue) {
				case 'network':
					uci.set('ddns', section_id, "ip_url",null);
					uci.set('ddns', section_id, "ip_interface",null);
					uci.set('ddns', section_id, "ip_script",null);
					break;
				case 'web':
					uci.set('ddns', section_id, "ip_network",null);
					uci.set('ddns', section_id, "ip_interface",null);
					uci.set('ddns', section_id, "ip_script",null);
					break;
				case 'interface':
					uci.set('ddns', section_id, "ip_network",null);
					uci.set('ddns', section_id, "ip_url",null);
					uci.set('ddns', section_id, "ip_script",null);
					break;
				case 'script':
					uci.set('ddns', section_id, "ip_network",null);
					uci.set('ddns', section_id, "ip_url",null);
					uci.set('ddns', section_id, "ip_interface",null);
					break;
				default:
					break;
			};

			return uci.set('ddns', section_id, 'ip_source', formvalue )
		};

		// ip_network

		o = s.taboption('advanced', widgets.NetworkSelect, 'ip_network', _("Network"),
		_("Defines the network to read systems IP-Address from"));
		o.depends('ip_source','network');
		o.modalonly = true;
		o.default = 'wan';
		o.multiple = false;

		// ip_url

		o = s.taboption('advanced', form.Value, 'ip_url', _("URL to detect"),
		_("Defines the Web page to read systems IP-Address from" + '<br>' +
		_('Example for IPv4' + ': http://checkip.dyndns.com') + '<br>' +
		_('Example for IPv6' + ': http://checkipv6.dyndns.com')));
		o.depends("ip_source", "web")

		o.modalonly = true;

		// ip_interface

		o = s.taboption('advanced', widgets.DeviceSelect, 'ip_interface', _("Interface"),
		_("Defines the interface to read systems IP-Address from"));

		o.modalonly = true;
		o.depends("ip_source", "interface")
		o.multiple = false;
		o.default = 'wan';

		// ip_script

		o = s.taboption('advanced', form.Value, 'ip_script', _("Script"),
		_("User defined script to read systems IP-Address"));

		o.modalonly = true;
		o.depends("ip_source", "script")
		o.placeholder = "/path/to/script.sh"

		// interface

		o = s.taboption('advanced', widgets.DeviceSelect, 'interface', _("Event Network"),
		_("Network on which the ddns-updater scripts will be started"));

		o.modalonly = true;
		o.multiple = false;
		o.default = 'wan';
		o.depends("ip_source", "web");
		o.depends("ip_source", "script");

		// interface_show

		o = s.taboption('advanced', form.DummyValue, '_interface', _("Event Network"),
		_("Network on which the ddns-updater scripts will be started"));
		o.depends("ip_source", "interface");
		o.depends("ip_source", "network");
		o.forcewrite = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return uci.get('ddns', section_id, 'interface') || _('This will be autoset to the selected interface');
		};
		o.write = function(section_id) {
			var opt = this.section.children.filter(function(o) { return o.option == 'ip_source' })[0].formvalue(section_id);
			var val = this.section.children.filter(function(o) { return o.option == 'ip_'+opt })[0].formvalue(section_id);
			return uci.set('ddns', section_id, 'interface', val);
		};

		// bind_network

		if (env['has_bindnet']) {
			o = s.taboption('advanced', widgets.ZoneSelect, 'bind_network', _("Bind Network"),
				_('OPTIONAL: Network to use for communication') + '<br>' +
				_("Network on which the ddns-updater scripts will be started"));
			o.depends("ip_source", "web");
			o.optional = true;
			o.rmempty = true;
			o.modalonly = true;
		}

		// force_ipversion

		if (env['has_forceip']) {
			o = s.taboption('advanced', form.Flag, 'force_ipversion', _("Force IP Version"),
				_('OPTIONAL: Force the usage of pure IPv4/IPv6 only communication.'));
			o.optional = true;
			o.rmempty = true;
			o.modalonly = true;
		}

		// dns_server

		if (env['has_dnsserver']) {
			o = s.taboption("advanced", form.Value, "dns_server",
				_("DNS-Server"),
				_("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") + "<br />" +
				_("Format: IP or FQDN"));
			o.placeholder = "mydns.lan"
			o.optional = true;
			o.rmempty = true;
			o.modalonly = true;
		}

		// force_dnstcp

		if (env['has_bindhost']) {
			o = s.taboption("advanced", form.Flag, "force_dnstcp",
				_("Force TCP on DNS"),
				_("OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."));
			o.optional = true;
			o.rmempty = true;
			o.modalonly = true;
		}

		// proxy

		if (env['has_proxy']) {
			o = s.taboption("advanced", form.Value, "proxy", _("PROXY-Server"),
				_("OPTIONAL: Proxy-Server for detection and updates.") + "<br />" +
				_("Format") + ": " + '<b>' + "[user:password@]proxyhost:port" + '</b>' + "<br />" +
				_("IPv6 address must be given in square brackets") + ": " +
				'<b>' + " [2001:db8::1]:8080" + '</b>');
			o.optional = true;
			o.rmempty = true;
			o.modalonly = true;
		}

		// use_syslog

		o = s.taboption("advanced", form.ListValue, "use_syslog", _("Log to syslog"),
			_("Writes log messages to syslog. Critical Errors will always be written to syslog."));
		o.modalonly = true;
		o.placeholder = "2"
		o.optional = true;
		o.value("0", _("No logging"))
		o.value("1", _("Info"))
		o.value("2", _("Notice"))
		o.value("3", _("Warning"))
		o.value("4", _("Error"))

		// use_logfile

		o = s.taboption("advanced", form.Flag, "use_logfile", _("Log to file"));
		o.default = '1';
		o.optional = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			this.description = _("Writes detailed messages to log file. File will be truncated automatically.") + "<br>" +
			_("File") + ': "' + logdir + '/' + section_id + '.log"';
			return uci.get('ddns', section_id, 'use_logfile');
		};

		// TAB Timer

		// check_interval
		o = s.taboption("timer", form.Value, "check_interval", _("Check Interval"));
		o.placeholder = "30";
		o.modalonly = true;
		o.datatype = 'uinteger';

		o.validate = function(section_id, formvalue) {
			var unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
				time_to_sec = time_res[unit || 'minutes'] * formvalue;

			if (formvalue && time_to_sec < 300)
				return _('Values below 5 minutes == 300 seconds are not supported');

			return true;

		};

		// check_interval
		o = s.taboption("timer", form.ListValue, "check_unit",'Check Unit');
		o.description = _("Interval unit to check for changed IP");
		o.modalonly = true;
		o.default  = "minutes"
		o.value("seconds", _("seconds"));
		o.value("minutes", _("minutes"));
		o.value("hours", _("hours"));

		// force_interval

		o = s.taboption("timer", form.Value, "force_interval", _("Force Interval"));
		o.description = _("Interval to force updates send to DDNS Provider" + "<br />" +
		"Setting this parameter to 0 will force the script to only run once");
		o.placeholder = "72";
		o.optional = true;
		o.modalonly = true;
		o.datatype = 'uinteger';

		o.validate = function(section_id, formvalue) {

			if (!formvalue)
				return true;

			var check_unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
				check_val = this.section.children.filter(function(o) { return o.option == 'check_interval' })[0].formvalue(section_id),
				force_unit = this.section.children.filter(function(o) { return o.option == 'force_unit' })[0].formvalue(section_id),
				check_to_sec = time_res[check_unit || 'minutes'] * ( check_val || '30'),
				force_to_sec = time_res[force_unit || 'minutes'] * formvalue;

			if (force_to_sec != 0 && force_to_sec < check_to_sec)
				return _("Values lower 'Check Interval' except '0' are not supported");

			return true;
		};

		// force_unit

		o = s.taboption("timer", form.ListValue, "force_unit",'Force Unit');
		o.description = _("Interval unit to force updates send to DDNS Provider");
		o.modalonly = true;
		o.optional = true;
		o.default  = "minutes"
		o.value("minutes", _("minutes"));
		o.value("hours", _("hours"));
		o.value("days", _("days"));

		// retry_count

		o = s.taboption("timer", form.Value, "retry_count", _("Error Retry Counter"));
		o.description = _("On Error the script will stop execution after given number of retrys")
		+ "<br />"
		+ _("The default setting of '0' will retry infinite.");
		o.placeholder = "0";
		o.optional = true;
		o.modalonly = true;
		o.datatype = 'uinteger';

		// retry_interval

		o = s.taboption("timer", form.Value, "retry_interval", _("Error Retry Interval"));
		o.description = _("On Error the script will stop execution after given number of retrys")
		+ "<br />"
		+ _("The default setting of '0' will retry infinite.");
		o.placeholder = "60";
		o.optional = true;
		o.modalonly = true;
		o.datatype = 'uinteger';

		// retry_unit

		o = s.taboption("timer", form.ListValue, "retry_unit",'Retry Unit');
		o.description = _("On Error the script will retry the failed action after given time");
		o.modalonly = true;
		o.optional = true;
		o.default  = "seconds"
		o.value("seconds", _("seconds"));
		o.value("minutes", _("minutes"));

		// TAB logview

		o = s.taboption("logview", form.DummyValue, '_read_log', '');
		o.depends('use_logfile','1');
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return E([], [
				E('button', {
				'class': 'cbi-button cbi-button-apply',
				'click': L.ui.createHandlerFn(this, function() {
					var o = this.section.children.filter(function(o) { return o.option == '_logview' })[0];
					return callGetLogServices(section_id).then(L.bind(o.update_log, o));
				})
			}, _('Read / Reread log file'))]);
		};

		o = s.taboption("logview", form.DummyValue, "_logview");
		o.depends('use_logfile','1');
		o.modalonly = true;

		o.update_log = L.bind(function(view, log_data) {
			return document.getElementById('log_area').innerHTML = log_data.result;
		}, o, this)

		o.render = L.bind(function() {
			return E([
				E('p', {}, _('This is the current content of the log file in ') + logdir + ' for this service.'),
				E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 20, 'readonly' : 'readonly', 'id' : 'log_area' }, _('Please press [Read] button') ))
			]);
		}, o, this)


		// Advanced Configuration Section

		s = m.section(form.NamedSection, 'global', 'ddns', _('Global Configuration'));
		s.description = _('Configure here the details for all Dynamic DNS services including this LuCI application.')
			+ '<br /><strong>'
			+ _("It is NOT recommended for casual users to change settings on this page.")
			+ '</strong><br />'
			+ '<a href="https://openwrt.org/docs/guide-user/base-system/ddns#section_ddns" target="_blank">'
			+ _('For detailed information about parameter settings look here.')
			+ '</a>';
		s.addremove = false;

		o = s.option(form.Flag, 'upd_privateip', _("Allow non-public IP's"));
		o.description = _("Non-public and by default blocked IP's") + ':'
		+ '<br /><strong>IPv4: </strong>'
		+ '0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16'
		+ '<br /><strong>IPv6: </strong>'
		+ '::/32, f000::/4"';
		o.default = "0";
		o.optional = true;

		o = s.option(form.Value, 'ddns_dateformat', _('Date format'));
		o.description = '<a href="http://www.cplusplus.com/reference/ctime/strftime/" target="_blank">'
			+ _("For supported codes look here")
			+ '</a><br>' +
			_('Current setting: ') + '<b>' + status['_curr_dateformat'] + '</b>';
		o.default = "%F %R"
		o.optional = true;
		o.rmempty = true;

		o = s.option(form.Value, 'ddns_rundir', _('Status directory'));
		o.description = _('Directory contains PID and other status information for each running section.');
		o.default = "/var/run/ddns";
		o.optional = true;
		o.rmempty = true;

		o = s.option(form.Value, 'ddns_logdir', _('Log directory'));
		o.description = _('Directory contains Log files for each running section.');
		o.default = "/var/log/ddns";
		o.optional = true;
		o.rmempty = true;
		o.validate = function(section_id, formvalue) {
			if (formvalue.indexOf('../') !== -1)
				return _('"../" not allowed in path for Security Reason.')

			return true;
		}

		o = s.option(form.Value, 'ddns_loglines', _('Log length'));
		o.description = _('Number of last lines stored in log files');
		o.datatype = 'min(1)';
		o.default = '250';

		if (env['has_wget'] && env['has_curl']) {

			o = s.option(form.Flag, 'use_curl', _('Use cURL'));
			o.description = _('If Wget and cURL package are installed, Wget is used for communication by default.');
			o.default = "0";
			o.optional = true;
			o.rmempty = true;

		}

		return m.render().then(L.bind(function(m, nodes) {
			L.Poll.add(L.bind(function() {
				return Promise.all([
					this.callDDnsGetServicesStatus(),
					callDDnsGetStatus()
				]).then(L.bind(this.poll_status, this, nodes));
			}, this), 5);
			return nodes;
		}, this, m));
	}
});