class ServerManager extends RootMenuApp

	@label: -> "admin.menu.servermanager"

	@group: ->
		"administration"

	@submenu: ->
		"administration"

	@is_allowed: ->
		if ez5.version("6")
			return false
		if ez5.session.hasSystemRight("root", "server.status")
			return true
		else
			return false

	@path: -> ["servermanager"]

	readOpts: ->
		super()
		@config = []

	load: (ev, info) ->
		super()
		@pane = new CUI.BorderLayout()
		ez5.rootLayout.replace(@pane, "center")

		new CUI.WaitBlock
			element: @pane.center()
			text: $$("api.server.loading")
		.show()
		@getStatus()
		CUI.resolvedPromise()

	unload: ->
		super()
		@pane?.destroy()
		@tabs?.destroy()
		@pane = null
		@tabs = null
		CUI.resolvedPromise()

	getStatus: () ->
		if @__purging
			return CUI.resolvedPromise()

		ez5.server
			url: ez5.pluginManager.getPlugin("server").getPluginURL() + "/status"
			handle_error: () =>
				if @__purging
					return true
		.done (@status) =>
			if not @isLoaded()
				return
			@show()

	show: ->
		if not @pane
			return

		if not @tabs
			tabs = []

		for info_group in @status.info_groups
			cls = info_group.name
			if cls == "_server_time"
				continue
			content = @renderInfoGroup(info_group)
			if tabs
				tabs.push(
					name: cls
					text: $$("api.server.status.class.#{cls}")
					content: content
				)
			else if @tabs.hasTab(cls)
				CUI.dom.replace(@tabs.getTab(cls).getBody(), content)
			else
				# tab is new, we need to reload
				@tabs.destroy()
				@tabs = null
				return @show()

		if tabs


			if ez5.session.hasSystemRight("root")
				post_opts = ez5.session.config.defaults.server.api?.settings or {}

				menu_button = new LocaButton
					loca_key: "server.manager.button.menu"
					menu:
						items: =>
							[
								loca_key: "server.manager.button.purgeall"
								disabled: not post_opts.purgeall
								onClick: =>
									@__purge("purgeall")
							,
								loca_key: "server.manager.button.purgedata"
								disabled: not post_opts.purgedata
								onClick: =>
									@__purge("purgedata")
							,
								loca_key: "server.manager.button.reindex"
								disabled: not post_opts.reindex
								onClick: =>
									@__reindex()
							,
								loca_key: "server.manager.button.restart"
								disabled: not post_opts.restart
								onClick: =>
									@__restart()
							,
								loca_key: "server.manager.button.updatecustomdata"
								disabled: not post_opts.updatecustomdata
								onClick: =>
									@__post_settings_simple("updatecustomdata", {})
							,
								loca_key: "server.manager.button.buildsuggest"
								disabled: not post_opts.buildsuggest
								onClick: =>
									@__post_settings_simple("buildsuggest", {})
							]

			@server_time = new CUI.Label()
			@tabs = new CUI.Tabs
				class: "ez5-server-manager-tabs"
				tabs: tabs
				padded: true
				footer_left: [
					loca_key: "server.manager.button.refresh"
					left: true
					onClick: (_, button) =>
						button.startSpinner()
						button.disable()
						@getStatus().always( =>
							button.stopSpinner()
							button.enable()
						)
				]
				footer_right: [
					@server_time
					menu_button
				]

			@pane.replace(@tabs, "center")

		@server_time.setText($$("api.server.status.server_time", time: @renderDate(@status._server_time)))

	__post_settings_simple: (call, json_data = undefined) ->

		ez5.splash.show("server.manager.spinner."+call)
		ez5.api.settings
			type: "POST"
			json_data: json_data
			api: "/" + call
		.always =>
			ez5.splash.hide()
		.done =>
			CUI.alert(
				markdown: true
				text: $$("server.manager.success."+call+".md")
			)
		return


	__reindex: ->
		CUI.confirm(
			markdown: true
			button_primary: "cancel"
			text: $$("server.manager.warning.confirm.reindex.md")
		).done( =>
			@__postSettingsAPI("reindex")
		)

	__restart: ->
		CUI.confirm(
			markdown: true
			button_primary: "cancel"
			text: $$("server.manager.warning.confirm.restart.md")
		).done( =>
			@__postSettingsAPI("restart")
		)

	__purge: (call) ->
		CUI.confirm(
			markdown: true
			button_primary: "cancel"
			text: $$("server.manager.warning."+call+".md")
		)
		.done =>
			inst = ez5.session.getInstance().name
			CUI.prompt(
				markdown: true
				class: "no-user-select"
				text: $$("server.manager.warning.confirm.md", instance: inst)
				button_primary: "cancel"
				min_length: inst.length
			)
			.done (value) =>
				if inst != value
					return
				@__postSettingsAPI(call)

	__postSettingsAPI: (call) ->
		ez5.eventPoller.stop()
		@__purging = true

		wait = false
		ez5.api.settings(
			type: "POST"
			api: "/" + call
			handle_error: (xhr) =>
				if xhr.status == 500 or xhr.status == 502
					# this is expected 500 local, 502 on docker installations
					wait = true
					return true
				return
		).always =>
			if not wait
				return

			ez5.splash.show("server.manager.splash.waiting")

			interval = window.setInterval( =>
				ez5.api.settings(
					timeout: 500
					handle_error: (xhr) =>
						return true
				).fail((xhr) =>
					if xhr.status == 500 or xhr.status == 502
						return true

					if xhr.CUI_statusText == "timeout"
						return true

					window.clearInterval(interval)
					ez5.splash.hide()
					CUI.problem(text: $$("server.manager.warning.reset_failed"))
				).done =>
					window.clearInterval(interval)
					ez5.splash.hide()

					if call == "restart" or call == "reindex"
						CUI.alert(
							markdown: true
							text: $$("server.manager.warning.#{call}.md")
							button_text_ok: $$("server.manager.button.reload")
						).done =>
							document.location.reload()
					else
						CUI.alert(
							markdown: true
							text: $$("server.manager.warning.reload.md")
							button_text_ok: $$("server.manager.button.reload")
						).done =>
							document.location.assign("/")
			, 2500)

	renderInfoGroup: (info_group) ->
		list = []

		for block in info_group.info

			switch(block.type)
				when "map"
					content = @renderMap(info_group.name, block)
				when "2d-map"
					content = @render2DMapVertical(info_group.name, block)
				else
					console.error("ServerManager.renderClass", "block.type \"#{block.type}\" unknown. Skipping. Block:", block)
			blk = new CUI.Block
				text: $$("api.server.status.block.#{info_group.name}.#{block.name}")
				padded: false
				content: content

			list.push(blk)

		new CUI.VerticalList
			content: list

	renderMap: (cls, block) ->
		tbl = CUI.dom.table("status-map")
		for value in block.data
			[v, format] = @renderValue(value)
			CUI.dom.append(tbl, CUI.dom.tr_one_row($$("api.server.status.value.#{cls}.#{block.name}.#{value.name}"), v))
		tbl

	# renders columns horizontally
	# This plugin is not using this method. Remove?
	render2DMapHorizontal: (cls, block) ->
		tbl = CUI.dom.table("status-2d-map status-2d-map-horizontal")
		arr = [ $$("api.server.status.headers.#{cls}.#{block.name}.#{block.headers.name}") ]
		for col in block.headers.values
			arr.push(col)

		CUI.dom.append(tbl, CUI.dom.tr_one_row.apply(@, arr))
		for value in block.data
			arr = [ $$("api.server.status.value.#{cls}.#{block.name}.#{value.name}") ]
			classes = [ "" ]
			for v, idx in value.values
				[v, _cls] = @renderValue(value, idx)
				arr.push(v)
				classes.push(_cls)

			tr = CUI.dom.tr_one_row.apply(@, arr)
			children = tr.children
			for _cls, idx in classes
				CUI.dom.addClass(children[idx], _cls)
			CUI.dom.append(tbl, tr)
		tbl

	# renders columns vertically
	render2DMapVertical: (cls, block) ->
		text = $$("api.server.status.headers.#{cls}.#{block.name}.#{block.headers.name}")
		columns = [
			text: if text then text else " " # Blank space to avoid using 'name' as text.
			name: "column-#{block.name}"
		]

		for value in block.data
			text = $$("api.server.status.value.#{cls}.#{block.name}.#{value.name}")
			columns.push(
				text: if text then text else " " # Blank space to avoid using 'name' as text.
				name: "column-#{value.name}"
			)

		rows = []
		for col, idx in block.headers.values
			row = [ block.headers.values[idx] ]
			for value in block.data
				[v] = @renderValue(value, idx)
				row.push(v)
			rows.push(row)

		return new CUI.Table
			bordered: true
			class: "status-2d-map status-2d-map-horizontal"
			header: true
			columns: columns
			rows: rows

	renderValue: (value, idx) ->
		if parseInt(idx) >= 0
			v = value.values[idx]
		else
			v = value.value

		switch value.type
			when "date"
				v = @renderDate(v)
				cls = "right"
			when "json"
				v = @renderJSON(v)
				cls = "right"
			when "error"
				v = @renderError(value)
				cls = "right"

		if value.unit
			switch value.unit
				when "bytes"
					v = ez5.format_filesize(v)
					cls = "right"
				when "completion"
					v = v.toFixed(2)+"%"
					cls = "right"
				when "s"
					v = ez5.format_seconds(v)
					cls = "right"
				else
					v += " "+value.unit
		[ v, cls ]

	renderDate: (str) ->
		ez5.format_date_and_time(str, true)

	renderJSON: (data) ->
		if not CUI.util.isArray(data) and not CUI.util.isPlainObject(data)
			return

		if CUI.util.isEmpty(data)
			return

		if CUI.util.isArray(data) and data.every((_data) => not CUI.util.isArray(_data) and not CUI.util.isPlainObject(_data))
			return data.join(", ")

		return new CUI.ObjectDumper(object: data)

	renderError: (value) ->
		new CUI.Label
			class: "ez5-server-manager-error-value"
			text:$$(value.error.code, value.error.parameters)
			markdown: true
			multiline: true
		.DOM


ez5.session_ready ->
	ez5.rootMenu.registerApp(ServerManager)
