require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "dialog"
require "filesearcher"
require "settings"
require "dialog"

FileHistory = {
	title_H = 40,	-- title height
	spacing = 36,	-- spacing between lines
	foot_H = 28,	-- foot height
	margin_H = 10,	-- horisontal margin

	-- state buffer
	history_files = {},
	files = {},
	result = {},
	items = 0,
	page = 0,
	current = 1,
	oldcurrent = 1,
	commands = nil,
}

function FileHistory:init(history_path)
	self:setPath("history")
	-- to initialize only once
	if not self.commands then self:addAllCommands() end
end

function FileHistory:setPath(newPath)
	self.path = newPath
	self:readDir("-c ")
	self.items = #self.files
	if self.items == 1 then
		return nil
	end
	self.page = 1
	self.current = 1
	return true
end

function FileHistory:readDir(order_criteria)
	self.history_files = {}
	self.files = {}
	local p = io.popen("ls "..order_criteria.."-1 "..self.path)
	for f in p:lines() do
		-- insert history files
		table.insert(self.history_files, {dir=self.path, name=f})
		-- and corresponding path & file items
		table.insert(self.files, {dir=HistoryToPath(f), name=HistoryToName(f)})
	end
	p:close()
end

function FileHistory:setSearchResult(keywords)
	self.result = {}
	if keywords == "" or keywords == " " then
		-- show all history
		self.result = self.files
	else
		-- select history files with keywords in the filename
		for __,f in pairs(self.files) do
			if string.find(string.lower(f.name), keywords) then
				table.insert(self.result,f)
			end
		end
	end
	self.keywords = keywords
	self.items = #self.result
	self.page = 1
	self.current = 1
	return self.items
end

function FileHistory:prevItem()
	if self.current == 1 then
		if self.page > 1 then
			self.current = self.perpage
			self.page = self.page - 1
			self.pagedirty = true
		end
	else
		self.current = self.current - 1
		self.markerdirty = true
	end
end

function FileHistory:nextItem()
	if self.current == self.perpage then
		if self.page < (self.items / self.perpage) then
			self.current = 1
			self.page = self.page + 1
			self.pagedirty = true
		end
	else
		if self.page ~= math.floor(self.items / self.perpage) + 1
			or self.current + (self.page-1)*self.perpage < self.items then
			self.current = self.current + 1
			self.markerdirty = true
		end
	end
end

function FileHistory:addAllCommands()
	self.commands = Commands:new{}
	self.commands:add(KEY_H, nil, "H",
		_("show help page"),
		function(self)
			HelpPage:show(0, G_height, self.commands)
			self.pagedirty = true
		end
	)
	self.commands:add(KEY_FW_UP, nil, "joypad up",
		_("previous item"),
		function(self)
			self:prevItem()
		end
	)
	self.commands:add(KEY_FW_DOWN, nil, "joypad down",
		_("next item"),
		function(self)
			self:nextItem()
		end
	)
	-- NuPogodi, 01.10.12: fast jumps to items at positions 10, 20, .. 90, 0% within the list
	local numeric_keydefs, i = {}
	for i=1, 10 do numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10)) end
	self.commands:addGroup("[1, 2 .. 9, 0]", numeric_keydefs,
		_("item at position 0%, 10% .. 90%, 100%"),
		function(self)
			local target_item = math.ceil(self.items * (keydef.keycode-KEY_1) / 9)
			self.current, self.page, self.markerdirty, self.pagedirty =
				gotoTargetItem(target_item, self.items, self.current, self.page, self.perpage)
		end
	)
	self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
		_("next page"),
		function(self)
			if self.page < (self.items / self.perpage) then
				if self.current + self.page*self.perpage > self.items then
					self.current = self.items - self.page*self.perpage
				end
				self.page = self.page + 1
				self.pagedirty = true
			else
				self.current = self.items - (self.page-1)*self.perpage
				self.markerdirty = true
			end
		end
	)
	self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
		_("previous page"),
		function(self)
			if self.page > 1 then
				self.page = self.page - 1
				self.pagedirty = true
			else
				self.current = 1
				self.markerdirty = true
			end
		end
	)
	self.commands:add(KEY_G, nil, "G", -- NuPogodi, 01.10.12: goto page No.
		_("goto page"),
		function(self)
			local n = math.ceil(self.items / self.perpage)
			local page = NumInputBox:input(G_height-100, 100, "Page:", "current page "..self.page.." of "..n, true)
			if pcall(function () page = math.floor(page) end) -- convert string to number
			and page ~= self.page and page > 0 and page <= n then
				self.page = page
				if self.current + (page-1)*self.perpage > self.items then
					self.current = self.items - (page-1)*self.perpage
				end
			end
			self.pagedirty = true
		end
	)
	self.commands:add(KEY_FW_RIGHT, nil, "joypad right",
		_("document details"),
		function(self)
			local file_entry = self.result[self.perpage*(self.page-1)+self.current]
			if file_entry.name == ".." then
				warningUnsupportedFunction()
				return
			end -- do not show details
			FileInfo:show(file_entry.dir,file_entry.name)
			self.pagedirty = true
		end
	)
	self.commands:add(KEY_S, nil, "S",
		_("invoke search inputbox"),
		function(self)
			-- NuPogodi, 30.09.12: be sure that something is found
			local old_keywords = self.keywords
			local old_data = self.result
			local old_page, old_current = self.page, self.current
			self.keywords = InputBox:input(G_height - 100, 100, "Search:", old_keywords)
			if self.keywords then
				self:setSearchResult(self.keywords)
			else
				self.keywords = old_keywords
			end
			if #self.result < 1 then
				InfoMessage:inform("No search hits ", DINFO_DELAY, 1, MSG_WARN)
				-- restoring the original data
				self.result = old_data
				self.items = #self.result
				self.keywords = old_keywords
				self.page = old_page
				self.current = old_current
			end
			self.pagedirty = true
		end
	)
	self.commands:add({KEY_F, KEY_AA}, nil, "F, Aa",
		_("change font faces"),
		function(self)
			Font:chooseFonts()
			self.pagedirty = true
		end
	)
	self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "Enter",
		_("open selected document"),
		function(self)
			local file_entry = self.result[self.perpage*(self.page-1)+self.current]
			file_full_path = file_entry.dir .. "/" .. file_entry.name
			if FileExists(file_full_path) then
				openFile(file_full_path)
				--[[
				-- reset height and item index if screen has been rotated
				-- not needed because we force portrait mode on document close
				local item_no = self.perpage * (self.page - 1) + self.current
				self.perpage = math.floor(G_height / self.spacing) - 2
				self.current = item_no % self.perpage
				self.page = math.floor(item_no / self.perpage) + 1
				--]]
				self:init()
				self:setSearchResult(self.keywords)
				self.pagedirty = true
			else
				InfoMessage:inform("File does not exist ", DINFO_DELAY, 1, MSG_ERROR)
			end
		end
	)
	self.commands:add(KEY_DEL, nil, "Del",
		_("delete history entry"),
		function(self)
			local file_entry = self.result[self.perpage*(self.page-1)+self.current]
			local file_to_del = file_entry.dir .. "/" .. file_entry.name
			if InfoMessage.InfoMethod[MSG_CONFIRM] == 0 then -- silent regime
				os.remove(DocToHistory(file_to_del))
				self:init()
				self:setSearchResult(self.keywords)
			else
				InfoMessage:inform("Press 'Y' to confirm ", DINFO_NODELAY, 0, MSG_CONFIRM)
				if ReturnKey() == KEY_Y then
					os.remove(DocToHistory(file_to_del))
					self:init()
					self:setSearchResult(self.keywords)
				end
			end
			self.pagedirty = true
			if self.items == 0 then
				return "break"
			end
		end
	)
	self.commands:add(KEY_SPACE, nil, "Space",
		_("refresh page manually"),
		function(self)
			self.pagedirty = true
		end
	)
	self.commands:add(KEY_BACK, nil, "Back",
		_("back"),
		function(self)
			return "break"
		end
	)
end

function FileHistory:choose(keywords)
	self.perpage = math.floor(G_height / self.spacing) - 2
	self.pagedirty = true
	self.markerdirty = false

	-- NuPogodi, 30.09.12: immediate quit (no redraw), if empty
	if self:setSearchResult(keywords) < 1 then
		InfoMessage:inform(_("No reading history "), DINFO_DELAY, 1, MSG_WARN)
		return nil
	end

	while true do
		local cface = Font:getFace("cfont", 22)
		local tface = Font:getFace("tfont", 25)
		local fface = Font:getFace("ffont", 16)

		if self.pagedirty then
			self.markerdirty = true
			fb.bb:paintRect(0, 0, G_width, G_height, 0)
			-- draw header
			local header = string.format(_("Last Documents (%d items)"), self.items)
			if self.keywords ~= "" and self.keywords ~= " " then
				--header = header .. " (filter: \'" .. string.upper(self.keywords) .. "\')"
				header = "Search Results for \'"..string.upper(self.keywords).."\'"
			end
			DrawTitle(header,self.margin_H,0,self.title_H,3,tface)
			-- draw found results
			for c = 1, self.perpage do
				local i = (self.page - 1) * self.perpage + c
				if i <= self.items then
					y = self.title_H + (self.spacing * c) + 4
					local ftype = string.lower(string.match(self.result[i].name, ".+%.([^.]+)") or "")
					DrawFileItem(self.result[i].name,self.margin_H,y,ftype)
				end
			end
			-- draw footer
			all_page = math.ceil(self.items/self.perpage)
			DrawFooter("Page "..self.page.." of "..all_page,fface,self.foot_H)
		end

		if self.markerdirty then
			if not self.pagedirty then
				if self.oldcurrent > 0 then
					y = self.title_H + (self.spacing * self.oldcurrent) + 12
					fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 0)
					Screen:refresh(1, nil, self.margin_H, y, G_width - 2 * self.margin_H, 3)
				end
			end
			-- draw new marker line
			y = self.title_H + (self.spacing * self.current) + 12
			fb.bb:paintRect(self.margin_H, y, G_width - 2 * self.margin_H, 3, 15)
			if not self.pagedirty then
				Screen:refresh(1, nil, self.margin_H, y, G_width - 2 * self.margin_H, 3)
			end
			self.oldcurrent = self.current
			self.markerdirty = false
		end

		if self.pagedirty then
			Screen:refresh(0)
			self.pagedirty = false
		end

		local ev = input.saveWaitForEvent()
		ev.code = adjustKeyEvents(ev)
		if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
			keydef = Keydef:new(ev.code, getKeyModifier())
			Debug("key pressed: "..tostring(keydef))

			command = self.commands:getByKeydef(keydef)
			if command ~= nil then
				Debug("command to execute: "..tostring(command))
				ret_code = command.func(self, keydef)
			else
				Debug("command not found: "..tostring(command))
			end

			if ret_code == "break" then
				break
			end

			if self.selected_item ~= nil then
				Debug("# selected "..self.selected_item)
				return self.selected_item
			end
		end -- if
	end -- while true
	return nil
end
