-- Settings

SettingsRestartDialog = {}

function 	SettingsRestartDialog.new()
	local ret = {}
	setmetatable(ret, { __index = SettingsRestartDialog })

	ret:buildWidget()

	return ret
end

function SettingsRestartDialog:buildWidget()
	self.widget = guiManager:createWidget()
	self.widget:loadMainSheet("SettingsRestartDialog.layout", "SettingsRestartDialog")

	self.window = self.widget:getMainWindow()
	self.window:subscribeEvent("CloseClicked", self.CloseClicked, self)

	self.okButton = self.widget:getWindow("OKButton")
	self.okButton:subscribeEvent("Clicked", self.CloseClicked, self)

	-- make it a modal window to prevent user from missing the info
	self.window:setModalState(true)
	-- we fire this to start the ShowTransition
	self.window:fireEvent("Shown", CEGUI.WindowEventArgs.new(self.window))
end

function SettingsRestartDialog:CloseClicked(agrs)
	self:destroy()
	return true
end

function SettingsRestartDialog:destroy()
	guiManager:destroyWidget(self.widget)
	self.widget = nil
end

SettingsUnappliedChangesDialog = {}

function SettingsUnappliedChangesDialog.new(settingsWidget)
	local ret = {}
	setmetatable(ret, { __index = SettingsUnappliedChangesDialog })

	ret:buildWidget()
	ret.settingsWidget = settingsWidget

	return ret
end

function SettingsUnappliedChangesDialog:buildWidget()
	self.widget = guiManager:createWidget()
	self.widget:loadMainSheet("SettingsUnappliedChangesDialog.layout", "SettingsUnappliedChangesDialog")

	self.window = self.widget:getMainWindow()

	self.applyButton = self.widget:getWindow("ApplyButton")
	self.applyButton:subscribeEvent("Clicked", self.ApplyClicked, self)

	self.discardButton = self.widget:getWindow("DiscardButton")
	self.discardButton:subscribeEvent("Clicked", self.DiscardClicked, self)

	-- make it a modal window to prevent user from missing the info
	self.window:setModalState(true)
	-- we fire this to start the ShowTransition
	self.window:fireEvent("Shown", CEGUI.WindowEventArgs.new(self.window))
end

function SettingsUnappliedChangesDialog:destroy()
	guiManager:destroyWidget(self.widget)
	self.widget = nil
end

function SettingsUnappliedChangesDialog:ApplyClicked(agrs)
	self:destroy()

	self.settingsWidget:applyAllValues()
	self.settingsWidget:hide()

	return true
end

function SettingsUnappliedChangesDialog:DiscardClicked(agrs)
	self:destroy()

	self.settingsWidget:discardAllValues()
	self.settingsWidget:hide()

	return true
end

SettingsWidget = {}

function SettingsWidget:buildWidget()

	self.widget = guiManager:createWidget()
	self.widget:loadMainSheet("Settings.layout", "Settings")

	self.window = self.widget:getMainWindow()
	self.window:subscribeEvent("CloseClicked", self.CloseClicked, self)

	self.okButton = self.widget:getWindow("OKButton")
	self.okButton:subscribeEvent("Clicked", self.OkClicked, self)

	self.applyButton = self.widget:getWindow("ApplyButton")
	self.applyButton:subscribeEvent("Clicked", self.ApplyClicked, self)

	self.cancelButton = self.widget:getWindow("CancelButton")
	self.cancelButton:subscribeEvent("Clicked", self.CloseClicked, self)

	self.tabs = self.widget:getWindow("Tabs")

	self:buildSettingsUi()

	self:hide()
	self.widget:registerConsoleVisibilityToggleCommand("settings")

	local configService = emberServices:getConfigService()
	local valueChangedCall = function(section, key)
		self:EventChangedConfigItem(section, key)
	end
	connect(self.connectors, configService.EventChangedConfigItem, valueChangedCall)
end

function SettingsWidget:shutdown()
	if self.settingsRestartDialogInstance then
		self.settingsRestartDialogInstance:destroy()
		self.settingsRestartDialogInstance = nil
	end
	if self.settingsUnappliedChangesDialogInstance then
		self.settingsUnappliedChangesDialogInstance:destroy()
		self.settingsUnappliedChangesDialogInstance = nil
	end

	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			if data.representation then
				local window = data.representation:getGuiRoot()
				if window:getParent() then
					window:getParent():removeChild(window)
				end
			end
		end
	end

	self.settings = nil
	disconnectAll(self.connectors)
	guiManager:destroyWidget(self.widget)
end

function SettingsWidget:buildSettingsUi()
	--This is a place where the settings contents are declared and (later) used to construct the GUI
	--to manipulace them

	local Representations = Ember.OgreView.Gui.Representations

	-- The declaration syntax described:
	-- *********************************
	--
	-- self.settings is an ordered array of tables, each of these tables represents a settings tab
	--
	-- keys of each settings tab
	-- label           - the text displayed in the tab's button
	-- helpString      - the text displayed at the top in the tab (when it's activated)
	--
	-- contents        - each settings tab contains ordered set of entries in its "contents" key

	-- meaning of various entry keys:
	-- label           - simply the text displayed to the left of the representation showing that particular settings entry
	-- helpString      - text that appears as a tooltip when you hold your mouse over the line containing the settings entry
	-- section and key - both varconf specific values, refer to varconf for a more detailed explanation
	-- representationFactory - a lua function that will construct a representation using passed data
	-- requiresRestart - if true user will be warned upon changing this that Ember should be restarted for the changes
	--                 - to take effect (optional and defaults to false)
	--
	-- Quick troubleshooting tip: Make sure the representationFactory anonymous function RETURNS the created representation
	--                            instance. I spent 15 minutes assuming it does and couldn't understand why it was being nil
	self.settings = {
		{
			label = "General",
			description = "Settings that don't fit into other category.",

			contents = {
				{
					label = "Startup help",
					helpString = "if true, the startup help window will be shown at startup",

					section = "general",
					key = "startuphelp",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
					requiresRestart = true,
				},
				{
					label = "Log chat messages",
					helpString = "If true, all chat message will be logged",

					section = "general",
					key = "logchatmessages",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Chat bubbles time shown",
					helpString = "How long are chat messages shown (in seconds)",

					section = "ingamechatwidget",
					key = "timeshown",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 60, true)
					end,
				},
				{
					label = "Chat bubbles distance shown",
					helpString = "How far do you have to go before chat messages disappear",

					section = "ingamechatwidget",
					key = "distanceshown",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},
				{
					label = "Desired FPS",
					helpString = "FPS capping - used to prevent using more excessive resources. 0 disables FPS cap.",

					section = "general",
					key = "desiredfps",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 150, true)
					end,
				}
			},
		},
		{
			label = "Graphics",
			description = "Groups visual settings affecting rendering quality. Many of these can deteriorate performance quite a lot so be careful.",

			contents = {
				{
					label = "Automatic Graphics Settings",
					helpString = "Sets whether the graphics settings are managed automatically",

					section = "graphics",
					key = "autoadjust",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Level",
					helpString = "General graphics level",

					section = "graphics",
					key = "level",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "low", "medium", "high" }
				},
				{
					label = "Render Distance",
					helpString = "Render distance in percentage of maximum distance",

					section = "graphics",
					key = "renderdistance",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},
				{
					label = "Level of detail bias",
					helpString = "Affects the detail level of all entities displayed",

					section = "graphics",
					key = "lodbias",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},
				--FIXME: Removed from Ember, not effective
				--[[{
					label = "Fresnel water",
					helpString = "More realistic and performance demanding water",
					
					section = "graphics",
					key = "fresnelwater",
					
					representationFactory = function(value) return Representations["CheckboxRepresentation<varconf::Variable>"].new(value) end,
				},--]]
				{
					label = "Foliage",
					helpString = "Render foliage over the terrain",

					section = "graphics",
					key = "foliage",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Foliage Density",
					helpString = "Density of foliage in percentage",

					section = "graphics",
					key = "foliagedensity",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},
				{
					label = "Foliage Distance",
					helpString = "Foliage Distance in a percentage of max value",

					section = "graphics",
					key = "foliagefardistance",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},

				--FIXME: not effective for now
				--[[{
					label = "Double buffered",
					helpString = "If set to true, the application will be double buffered, which means that everything is rendered into a separate backbuffer, which is then copied to the main screen buffer when appropriate. This will in some cases reduce tearing.",
					
					section = "graphics",
					key = "doublebuffered",
					
					representationFactory = function(value) return Representations["CheckboxRepresentation<varconf::Variable>"].new(value) end,
				},--]]
				{
					label = "Shadow texture size",
					helpString = "The bigger this number, the more accurate the shadows will be",

					section = "shadows",
					key = "texturesize",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, int>"].new(value, true)
					end,
					suggestions = { "256", "512", "1024", "2048", "4096" },
				},
				{
					label = "Shadow far distance",
					helpString = "If the shadows are to be further than this value, they won't be rendered",

					section = "shadows",
					key = "fardistance",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 1000, true)
					end,
				},
				{
					label = "Shadow level of detail",
					helpString = "Affects the model used to generate the shadow, lower values result in overall lower detail shadows",

					section = "shadows",
					key = "shadowlodbias",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 100, true)
					end,
				},
				{
					label = "Use aggressive focus region",
					helpString = "Sets whether or not to use the more aggressive approach to deciding on the focus region or not.",

					section = "shadows",
					key = "useaggressivefocusregion",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Preferred terrain technique",
					helpString = "The preferred terrain technique. Available values are: ShaderNormalMapped, Shader, Base",

					section = "terrain",
					key = "preferredtechnique",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "ShaderNormalMapped", "Shader" },
				},
				{
					label = "Terrain page size",
					helpString = "The size of single terrain pages. Affects how fast pages are loaded at the start of the game and how much memory is used.",

					section = "terrain",
					key = "pagesize",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, int>"].new(value, true)
					end,
					suggestions = { "64", "128", "256", "512", "1024", "2048" },
				},
				{
					label = "Terrain load radius",
					helpString = "The distance from the camera at which terrain pages are loaded. Affects how fast the initial loading is as well as the memory usage and performance in-game.",

					section = "terrain",
					key = "loadradius",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, int>"].new(value, true)
					end,
					suggestions = { "100", "300", "500", "700", "900", "1100", "1300", "1500", "2000", "3000" },
				},

			},
		},
		{
			label = "Audio",
			description = "All settings related to audio output of the Ember client.",

			contents = {
				{
					label = "Enabled",
					helpString = "Controls whether sounds are played",

					section = "audio",
					key = "enabled",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Output",
					helpString = "Which sound output should be used",

					section = "audio",
					key = "output",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "surround" }
				},
			},
		},
		{
			label = "Input",
			description = "Groups various options regarding mouse and keyboard input devices.",

			contents = {
				{
					label = "Mouse sensitivity",
					helpString = "Affects mouse look only.",

					section = "input",
					key = "degreespermouseunit",

					representationFactory = function(value)
						return Representations["SliderRepresentation<varconf::Variable>"].new(value, 400, true)
					end,
				},
				{
					label = "Invert mouse look",
					helpString = "If true, the pitch of the camera will be inverted. Useful for people that are used to flight simulators.",

					section = "input",
					key = "invertcamera",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Catch mouse",
					helpString = "If true, Ember will catch the mouse. This means that the mouse cursor won't be able to move beyond the Ember window. ALT+TAB releases the mouse.",

					section = "input",
					key = "catchmouse",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Adjust camera to terrain",
					helpString = "If true, the camera will be adjusted to the terrain so that it never dips below the surface",

					section = "input",
					key = "adjusttoterrain",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Auto movement mode",
					helpString = "If true, Ember will automatically switch to movement mode after entering the world",

					section = "input",
					key = "automovementmode",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
			},
		},
		{
			label = "Servers",
			description = "Options regarding connecting to various servers",

			contents = {
				{
					label = "Connect to meta server",
					helpString = "Ember will connect to the meta server given below on startup.",

					section = "metaserver",
					key = "enabled",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Metaserver",
					helpString = "Which meta server should Ember connect to on startup",

					section = "metaserver",
					key = "server",

					representationFactory = function(value)
						return Representations["EditboxRepresentation<varconf::Variable, std::string>"].new(value)
					end,
				},
				{
					label = "Autoconnect",
					helpString = "If specified, Ember will connect to this server at startup automatically",

					section = "metaserver",
					key = "autoconnect",

					representationFactory = function(value)
						return Representations["EditboxRepresentation<varconf::Variable, std::string>"].new(value)
					end,
				},
				{
					label = "Minimum server version",
					helpString = "If set to something, the server browser will filter out all servers with versions lower than this. This is to prevent new users from connecting to old stale servers.",

					section = "metaserver",
					key = "minimumversion",

					representationFactory = function(value)
						return Representations["EditboxRepresentation<varconf::Variable, std::string>"].new(value)
					end,
				},
			},
		},
		-- TODO: It might be good to hide this in client final builds but for now it was decided to always show it
		{
			label = "Developer",
			description = "Only useful if you are troubleshooting or doing development.",

			contents = {
				{
					label = "Logging level",
					helpString = "",

					section = "general",
					key = "logginglevel",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "verbose", "info", "warning", "failure", "critical" }
				},
				{
					label = "Logging detailed",
					helpString = "",

					section = "general",
					key = "loggingdetailed",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "CEGUI Logging level",
					helpString = "",

					section = "cegui",
					key = "minimumlogginglevel",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "insane", "informative", "standard", "warnings", "errors" }
				},
				{
					label = "OGRE Logging level",
					helpString = "",

					section = "ogre",
					key = "loglevel",

					representationFactory = function(value)
						return Representations["ComboboxRepresentation<varconf::Variable, std::string>"].new(value, true)
					end,
					suggestions = { "trivial", "normal", "warning", "critical" }
				},
				{
					label = "Enable Lua debugging",
					helpString = "",

					section = "lua",
					key = "debug",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Use debug LOD colours for terrain",
					helpString = "",

					section = "terrain",
					key = "usedebuglodcolors",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Show 'inspect' menu option",
					helpString = "Turning this on will display the 'inspect' menu option for all entities, even when the user isn't logged in as ad admin character.",

					section = "authoring",
					key = "showinspectforall",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Show navigation tiles",
					helpString = "Shows the tiles built when navigating in the world.",

					section = "authoring",
					key = "visualizerecasttiles",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Show navigation path",
					helpString = "Shows the path used by navigation.",

					section = "authoring",
					key = "visualizerecastpath",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Show OGRE profiler",
					helpString = "Shows the OGRE profiler overlay, if OGRE has support for it.",

					section = "ogre",
					key = "profiler",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				},
				{
					label = "Print stack for slow frames",
					helpString = "Will print the stack for when a frame takes too long",

					section = "general",
					key = "slowframecheck",

					representationFactory = function(value)
						return Representations["CheckboxRepresentation<varconf::Variable>"].new(value)
					end,
				}
			},
		},
	}

	-- chew through settings declaration and construct UI for it
	for _, category in ipairs(self.settings) do
		if category.requiresRestart == nil then
			category.requiresRestart = false
		end

		local wnd = self:buildUiFor(category)
		self.tabs:addChild(wnd)
	end
end

function SettingsWidget:getDeclarationData(section, key)
	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			if (data.section == section) and (data.key == key) then
				return data
			end
		end
	end

	return nil
end

function SettingsWidget:buildUiFor(category)
	local ret = CEGUI.WindowManager.getSingleton():createWindow("EmberLook/ScrollablePane")
	ret:setText(category.label)
	ret:setProperty("Position", "{{0.0, 0.0}, {0.0, 0.0}}")
	ret:setProperty("Size", "{{1.0, 0.0}, {1.0, 0.0}}")

	-- you can think of the vertical layout container as a VBoxLayout in GTK or Vertical Layout in Qt4
	-- it simply puts its elements as tightly packed as possible after each other vertically
	-- in this case it represents category tab's list of entries
	local vbox = CEGUI.WindowManager.getSingleton():createWindow("VerticalLayoutContainer")
	local description = CEGUI.WindowManager.getSingleton():createWindow("EmberLook/StaticText")
	description:setText(category.description)
	description:setProperty("Size", "{{1.0, -1.0}, {0.0, 50.0}}")
	description:setProperty("HorzFormatting", "WordWrapLeftAligned")
	vbox:addChild(description)

	local configService = emberServices:getConfigService()

	for _, data in ipairs(category.contents) do
		local value = configService:getValue(data.section, data.key)

		local representation = data.representationFactory(value)
		local suggestions = data.suggestions

		-- if suggestions are omitted, make them "empty"
		if suggestions == nil then
			suggestions = {}
		end

		-- and each line in the entry vertical list is a horizontal layout (serves as a wrapper in this case)
		local hbox = CEGUI.WindowManager.getSingleton():createWindow("HorizontalLayoutContainer")

		local label = CEGUI.WindowManager.getSingleton():createWindow("EmberLook/StaticText")
		label:setText(data.label)
		label:setProperty("Size", "{{0.4, 0.0}, {0.0, 30.0}}")
		label:setProperty("FrameEnabled", "False")
		hbox:addChild(label)
		data.labelWnd = label

		for _, suggestion in ipairs(suggestions) do
			representation:addSuggestion(suggestion)
		end

		local representationGuiRoot = representation:getGuiRoot()
		representationGuiRoot:setProperty("Size", "{{0.6, 0}, {0.0, 30.0}}")
		hbox:addChild(representationGuiRoot)

		representationGuiRoot:setTooltipText(data.helpString)
		hbox:setTooltipText(data.helpString)

		-- This commented out portion of the code makes help string appear right to the representation
		-- In the end I decided to show help strings as a tooltip to save space
		--local helpStringLabel = CEGUI.WindowManager.getSingleton():createWindow("EmberLook/StaticText")
		--helpStringLabel:setText(data.helpString)
		--helpStringLabel:setProperty("Size", "{{0.5, -1.0}, {0.0, 30.0}}")
		--helpStringLabel:setProperty("FrameEnabled", "False")
		--helpStringLabel:setProperty("HorzFormatting", "WordWrapLeftAligned")
		--hbox:addChild(helpStringLabel)

		vbox:addChild(hbox)

		-- store the representation in data so that we can query it later (to get current value)
		data.representation = representation

		local localSection = data.section
		local localKey = data.key

		local valueChangedCall = function()
			self:RepresentationValueChanged(localSection, localKey)
		end
		connect(self.connectors, representation:getEventValueChangedSignal(), valueChangedCall)
	end

	ret:addChild(vbox)
	return ret
end

function SettingsWidget:hasChanges()
	-- Checks whether there are changed values in the settings
	-- returns: true if there are changes

	local configService = emberServices:getConfigService()

	-- go through everything and check whether we have changes
	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			if data.representation:hasChanges() then
				return true
			end
		end
	end

	return false
end

function SettingsWidget:applyAllValues()
	-- Applies all values
	-- returns: true if the changes required restart of Ember, false otherwise

	local configService = emberServices:getConfigService()
	local requiresRestart = false

	-- go through everything and apply the new values
	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			if data.representation:hasChanges() then
				configService:setValue(data.section, data.key, data.representation:getEditedValue(), varconf.USER)

				-- notify the representation that we applied our changes and it should alter it's original value
				data.representation:applyChanges()

				-- we call this to notify the representation that the varconf value has changed,
				-- the representation can stop notifying that it has changes if applicable
				self:RepresentationValueChanged(data.section, data.key)

				-- if this value changed and a change requires restart, we have to tell the user
				requiresRestart = requiresRestart or data.requiresRestart
			end
		end
	end

	self.applyButton:setEnabled(false)

	if requiresRestart then
		self.settingsRestartDialogInstance = SettingsRestartDialog.new()
	end

	return requiresRestart
end

function SettingsWidget:discardAllValues()
	-- Discards all edited values

	local configService = emberServices:getConfigService()

	-- go through everything and discard values
	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			data.representation:setEditedValue(data.representation:getOriginalValue())
		end
	end
end

function SettingsWidget:resetAllToDefault()
	local configService = emberServices:getConfigService()

	-- goes through representations and for each it puts the default value to it
	for _, category in ipairs(self.settings) do
		for _, data in ipairs(category.contents) do
			--local default = ...
			--data.representation:setEditedValue(default)
		end
	end
end

function SettingsWidget:hide()
	self.widget:hide()
end

function SettingsWidget:OkClicked(args)
	self:applyAllValues()
	self:hide()

	return true
end

function SettingsWidget:ApplyClicked(args)
	self:applyAllValues()

	return true
end

function SettingsWidget:CloseClicked(args)
	if self:hasChanges() then
		-- unapplied changes dialog takes care of discarding or applying the settings
		self.settingsUnappliedChangesDialogInstance = SettingsUnappliedChangesDialog.new(self)
	else
		self:hide()
	end

	return true
end

function SettingsWidget:RepresentationValueChanged(section, key)
	local data = self:getDeclarationData(section, key)

	-- only enable the apply button if we have changes
	self.applyButton:setEnabled(self:hasChanges())

	-- FIXME: For now I use an asterisk to show a settings entry has changes, this might be changed
	--        to something more artistic in the future
	if data.representation:hasChanges() then
		data.labelWnd:setText(data.label .. "*")
	else
		data.labelWnd:setText(data.label)
	end
end

function SettingsWidget:EventChangedConfigItem(section, key)
	local data = self:getDeclarationData(section, key)
	-- if we don't have these data declared, return immediately
	if data == nil then
		return
	end

	local configService = emberServices:getConfigService()
	local value = configService:getValue(section, key)

	-- If we had changes before the variable was externally changed we save them and reapply them
	-- to prevent loosing them

	-- This is a compromise I came up with to the problem, it seems to me that if the entry doesn't have any changes in it
	-- it doesn't make sense to preserve the old value but if user changes it and something else is changing it at the same
	-- time it changes the original value but the edited value is preserved.

	if data.representation:hasChanges() then
		local oldEdited = data.representation:getEditedValue()
		data.representation:setEditedValue(value)
		data.representation:applyChanges()
		data.representation:setEditedValue(oldEdited)
	else
		data.representation:setEditedValue(value)
		data.representation:applyChanges()
	end

	-- sync up the changed status of the representation
	self:RepresentationValueChanged(section, key)
end

local settingsInit = function()
	local settingsWidget = { connectors = {} }
	setmetatable(settingsWidget, { __index = SettingsWidget })
	settingsWidget:buildWidget()

	connect(settingsWidget.connectors, scriptingService.EventShutdown, function()
		settingsWidget:shutdown()
		settingsWidget = nil
		collectgarbage()
	end)
end
settingsInit()
