--// =============================================================================

--- ImageListView module

--- ImageListView fields.
-- Inherits from LayoutPanel.
-- @see layoutpanel.LayoutPanel
-- @table ImageListView
-- @string[opt = ""] dir initial directory
-- @tparam {func1, func2, ...} OnDirChange table of function listeners for directory change (default {})
ImageListView = LayoutPanel:Inherit{
	classname = "imagelistview",

	autosize = true,

	autoArrangeH = false,
	autoArrangeV = false,
	centerItems  = false,

	iconX     = 64,
	iconY     = 64,

	itemMargin    = {1, 1, 1, 1},

	selectable  = true,
	multiSelect = true,

	items = {},

	dir = '',

	useRTT = false;

	OnDirChange = {},
}

local this = ImageListView
local inherited = this.inherited

--// =============================================================================

local image_exts = {'.jpg', '.bmp', '.png', '.tga', '.dds', '.ico', '.gif', '.psd', '.tif'} --'.psp'

--// =============================================================================

function ImageListView:New(obj)
	obj = inherited.New(self, obj)
	obj:SetDir(obj.dir)
	return obj
end

--// =============================================================================

local function GetParentDir(dir)
	dir = dir:gsub("\\", "/")
	local lastChar = dir:sub(-1)
	if (lastChar == "/") then
		dir = dir:sub(1, -2)
	end
	local pos, b, e, match, init, n = 1, 1, 1, 1, 0, 0
	repeat
		pos, init, n = b, init + 1, n + 1
		b, init, match = dir:find("/", init, true)
	until (not b)
	if (n == 1) then
		return ''
	else
		return dir:sub(1, pos)
	end
end


local function ExtractFileName(filepath)
	filepath = filepath:gsub("\\", "/")
	local lastChar = filepath:sub(-1)
	if (lastChar == "/") then
		filepath = filepath:sub(1, -2)
	end
	local pos, b, e, match, init, n = 1, 1, 1, 1, 0, 0
	repeat
		pos, init, n = b, init + 1, n + 1
		b, init, match = filepath:find("/", init, true)
	until (not b)
	if (n == 1) then
		return filepath
	else
		return filepath:sub(pos + 1)
	end
end


local function ExtractDir(filepath)
	filepath = filepath:gsub("\\", "/")
	local lastChar = filepath:sub(-1)
	if (lastChar == "/") then
		filepath = filepath:sub(1, -2)
	end
	local pos, b, e, match, init, n = 1, 1, 1, 1, 0, 0
	repeat
		pos, init, n = b, init + 1, n + 1
		b, init, match = filepath:find("/", init, true)
	until (not b)
	if (n == 1) then
		return filepath
	else
		return filepath:sub(1, pos)
	end
end

--// =============================================================================

function ImageListView:_AddFile(name, imagefile)
	self:AddChild( LayoutPanel:New{
		width  = self.iconX + 10,
		height = self.iconY + 20,
		padding = {0, 0, 0, 0},
		itemPadding = {0, 0, 0, 0},
		itemMargin = {0, 0, 0, 0},
		rows = 2,
		columns = 1,
		useRTT = false;

		children = {
			Image:New{
				width  = self.iconX,
				height = self.iconY,
				passive = true,
				file = ':clr' .. self.iconX .. ', ' .. self.iconY .. ':' .. imagefile,
			},
			Label:New{
				width = self.iconX + 10,
				height = 20,
				align = 'center',
				autosize = false,
				caption = name,
			},
		},
	})
end


function ImageListView:ScanDir()
	local files = VFS.DirList(self.dir)
	local dirs  = VFS.SubDirs(self.dir)
	local imageFiles = {}
	for i = 1, #files do
		local f = files[i]
		local ext = (f:GetExt() or ""):lower()
		if (table.ifind(image_exts, ext))then
			imageFiles[#imageFiles + 1] = f
		end
	end


	self._dirsNum = #dirs
	self._dirList = dirs

	local n    = 1
	local items = self.items
	items[n] = '..'
	n = n + 1

	for i = 1, #dirs do
		items[n], n = dirs[i], n + 1
	end
	for i = 1, #imageFiles do
		items[n], n = imageFiles[i], n + 1
	end
	if (#items > n-1) then
		for i = n, #items do
			items[i] = nil
		end
	end

	self:DisableRealign()
		--// clear old
		self:ClearChildren()

		--// add ".."
		self:_AddFile('..', self.imageFolderUp)

		--// add dirs at top
		for i = 1, #dirs do
			self:_AddFile(ExtractFileName(dirs[i]), self.imageFolder)
		end

		--// add files
		for i = 1, #imageFiles do
			self:_AddFile(ExtractFileName(imageFiles[i]), imageFiles[i])
		end
	self:EnableRealign()
end


function ImageListView:SetDir(directory)
	self:DeselectAll()
	self.dir = directory
	self:ScanDir()
	self:CallListeners(self.OnDirChange, directory)

	if (self.parent) then
		self.parent:RequestRealign()
	else
		self:UpdateLayout()
		self:Invalidate()
	end
end


function ImageListView:GoToParentDir()
	self:SetDir(GetParentDir(self.dir))
end


function ImageListView:GotoFile(filepath)
	local dir = ExtractDir(filepath)
	local file = ExtractFileName(filepath)
	self.dir = dir
	self:ScanDir()
	self:Select(file)

	if (self.parent) then
		if (self.parent.classname == "scrollpanel") then
			local x, y, w, h = self:GetItemXY(next(self.selectedItems))
			self.parent:SetScrollPos(x + w*0.5, y + h*0.5, true)
		end

		self.parent:RequestRealign()
	else
		self:UpdateLayout()
		self:Invalidate()
	end
end

--// =============================================================================

function ImageListView:Select(item)
	if (type(item) == "number") then
		self:SelectItem(item)
	else
		local items = self.items
		for i = 1, #items do
			if (ExtractFileName(items[i]) == item) then
				self:SelectItem(i)
				return
			end
		end
		self:SelectItem(1)
	end
end

--// =============================================================================

function ImageListView:DrawItemBkGnd(index)
	local cell = self._cells[index]
	local itemPadding = self.itemPadding

	if (self.selectedItems[index]) then
		self:DrawItemBackground(cell[1] - itemPadding[1], cell[2] - itemPadding[2], cell[3] + itemPadding[1] + itemPadding[3], cell[4] + itemPadding[2] + itemPadding[4], "selected")
	else
		self:DrawItemBackground(cell[1] - itemPadding[1], cell[2] - itemPadding[2], cell[3] + itemPadding[1] + itemPadding[3], cell[4] + itemPadding[2] + itemPadding[4], "normal")
	end
end

--// =============================================================================

function ImageListView:HitTest(x, y)
	local cx, cy = self:LocalToClient(x, y)
	local obj = inherited.HitTest(self, cx, cy)
	if (obj) then
		return obj
	end
	local itemIdx = self:GetItemIndexAt(cx, cy)
	return (itemIdx >= 0) and self
end


function ImageListView:MouseDblClick(x, y)
	local cx, cy = self:LocalToClient(x, y)
	local itemIdx = self:GetItemIndexAt(cx, cy)

	if (itemIdx < 0) then
		return
	end

	if (itemIdx == 1) then
		self:SetDir(GetParentDir(self.dir))
		return self
	end

	if (itemIdx <= self._dirsNum + 1) then
		self:SetDir(self._dirList[itemIdx-1])
		return self
	else
		self:CallListeners(self.OnDblClickItem, self.items[itemIdx], itemIdx)
		return self
	end
end

--// =============================================================================
