--[[
	This file is part of NeuralView.

    NeuralView is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    NeuralView is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with NeuralView.  If not, see <http://www.gnu.org/licenses/>.
--]]

---
-- Dialog that allows the creation / manipulation of filters (or maps, as they
-- maps non numerical data to numerical data.
local FilterEditor, FilterEditorMT = nv_module("view.FilterEditor")

local Filter = require("core.Filter")

---
-- Constructor.
--
-- @param parent Parent window
-- @return New instance of FilterEditor 
function FilterEditor.new(parent)
	local self = {}
	setmetatable(self, FilterEditorMT)
	
	self:build_gui(parent)
	self.iter = gtk.TreeIter.new()
	
	return self
end

local CELL_LIMIT, CELL_VALUE = 0, 1

---
-- Builds the interface.
--
-- @private
function FilterEditor:build_gui(parent)
	self.dialog = gtk.Dialog.new()
	self.dialog:set("title", _"Filter editor", "transient-for", parent,
		"default-width", 400, "default-height", 300, "icon", NVIcon)
	self.dialog:add_buttons("gtk-cancel", gtk.RESPONSE_CANCEL, 
		"gtk-ok", gtk.RESPONSE_OK)
	self.vbox = self.dialog:get_content_area()
	
	-- treeview
	self.model = gtk.ListStore.new("gdouble", "gchararray")
	self.view = gtk.TreeView.new_with_model(self.model)
	local cell = gtk.CellRendererText.new()
	cell:set("editable", true)
	cell:connect("edited", self.cell_edited, {self, CELL_LIMIT})
	self.limitcol = gtk.TreeViewColumn.new_with_attributes(_"Upper limit", 
		cell, "text", 0)
	
	local cell = gtk.CellRendererText.new()
	cell:set("editable", true)
	cell:connect("edited", self.cell_edited, {self, CELL_VALUE})
	self.valuecol = gtk.TreeViewColumn.new_with_attributes(_"Value", 
		cell, "text", 1)
	
	self.view:append_column(self.limitcol)
	self.view:append_column(self.valuecol)
	self.selection = self.view:get_selection()
	self.selection:set_mode(gtk.SELECTION_MULTIPLE)
	
	self.scroll = gtk.ScrolledWindow.new()
	self.scroll:set("vscrollbar-policy", gtk.POLICY_AUTOMATIC,
		"hscrollbar-policy", gtk.POLICY_AUTOMATIC)
	self.scroll:add(self.view)
	
	-- add / remove / clear filter buttons
	self.button_box = gtk.VButtonBox.new()
	self.button_box:set("layout-style", gtk.BUTTONBOX_START)
	
	self.add = gtk.Button.new_from_stock("gtk-add")
	self.add:connect("clicked", self.add_row, self)
	self.add:set("tooltip-text", _"Add a new interval point")
	
	self.remove = gtk.Button.new_from_stock("gtk-remove")
	self.remove:connect("clicked", self.remove_row, self)
	self.remove:set("tooltip-text", _"Remove the selected interval points")
	
	self.button_box:add(self.add, self.remove)
	
	self.hbox = gtk.HBox.new(false, 0)
	self.hbox:pack_start(self.scroll, true, true, 0)
	self.hbox:pack_start(self.button_box, false, true, 0)
	
	self.vbox:pack_start(self.hbox, true, true, 0)
	self.vbox:show_all()
end

---
-- Prepares the interface for a new filter.
--
-- @private
function FilterEditor:prepare(filter)
	local model, iter = self.model, self.iter
	
	self.view:set("model", nil)
	model:clear()
	
	if filter then
		filter:foreach(
			function(value, label)
				model:append(self.iter)
				model:seto(self.iter, value, label)
			end)
	end
	
	self.view:set("model", model)
end

---
-- Transforms the user input into a filter.
function FilterEditor:get_filter()
	local model, iter = self.model, self.iter
	local valid = model:get_iter_first(iter)
	local filter = Filter.new()
	
	while valid do
		local value, label = model:get(iter, 0, 1)
		filter:add(value, label)
		valid = model:iter_next(iter)
	end
	
	filter:sort()
	
	return filter
end

---
-- Handles a cell edition.
--
-- @private
function FilterEditor:cell_edited(path, data)
	local self, cell = unpack(self)
	local value
	
	if cell == CELL_LIMIT then
		value = tonumber(data) 
	elseif cell == CELL_VALUE then
		value = data
	end
	
	if value then
		self.model:get_iter_from_string(self.iter, path)
		self.model:set(self.iter, cell, value)
	end
end

---
-- Adds a row to the editor.
--
-- @private
function FilterEditor:add_row()
	self.model:append(self.iter)
	self.model:seto(self.iter, 0, _"New value")
end

---
-- Removes the selected row from the editor.
--
-- @private
function FilterEditor:remove_row()
	local rows = self.selection:get_selected_rows(self.iter)
	
	for i = #rows, 1, -1 do
		self.model:get_iter_from_string(self.iter, rows[i])
		self.model:remove(self.iter)
	end
end

---
-- Runs the filter editor.
--
-- @param filter Filter to edit
-- @return New filter, or nil to clear the filter
function FilterEditor:run(filter)
	self:prepare(filter)
	
	local res = self.dialog:run()
	local ret
	self.dialog:hide()
	
	if res == gtk.RESPONSE_OK then
		ret = self:get_filter()
	else
		ret = filter
	end
	
	self:prepare()
	return ret 
end

return FilterEditor 
