-- Simple Skins mod for minetest (26th July 2017)
-- Adds a simple skin selector to the inventory, using inventory_plus
-- or by using the /skin command to bring up selection list.
-- Released by TenPlus1 and based on Zeg9's code under MIT license

skins = {}
skins.skins = {}
skins.modpath = minetest.get_modpath("simple_skins")
skins.armor = minetest.get_modpath("3d_armor")
skins.inv = minetest.get_modpath("inventory_plus")

-- Load support for intllib.
local MP = minetest.get_modpath(minetest.get_current_modname())
local S, NS = dofile(MP.."/intllib.lua")
local F = function(...) return minetest.formspec_escape(S(...)) end

-- load skin list
skins.list = {}
skins.add = function(skin)
	table.insert(skins.list, skin)
end

local id = 1
local f
while true do
	f = io.open(skins.modpath .. "/textures/character_" .. id .. ".png")
	if not f then break end
	f:close()
	skins.add("character_" .. id)
	id = id + 1
end

id = id - 1

-- load Metadata
skins.meta = {}
local f, data
for _, i in pairs(skins.list) do
	skins.meta[i] = {}
	f = io.open(skins.modpath .. "/meta/" .. i .. ".txt")
	data = nil
	if f then
		data = minetest.deserialize("return {" .. f:read('*all') .. "}")
		f:close()
	end
	data = data or {}
	skins.meta[i].name = data.name or ""
	skins.meta[i].author = data.author or ""
end

-- player load/save routines
skins.file = minetest.get_worldpath() .. "/simple_skins.mt"

skins.load = function()
	local input = io.open(skins.file, "r")
	local data = nil
	if input then
		data = input:read('*all')
	end
	if data and data ~= "" then
		local lines = string.split(data, "\n")
		for _, line in pairs(lines) do
			data = string.split(line, ' ', 2)
			skins.skins[data[1]] = data[2]
		end
		io.close(input)
	end
end

-- load player skins now
skins.load()

skins.save = function()
	local output = io.open(skins.file,'w')
	for name, skin in pairs(skins.skins) do
		if name and skin then
			output:write(name .. " " .. skin .. "\n")
		end
	end
	io.close(output)
end

-- skin selection page
skins.formspec = {}
skins.formspec.main = function(name)

	local selected = 1 -- select default
	local formspec = "size[7,7]"
		.. "bgcolor[#08080822;true]"
		.. "label[.5,2;" .. F("Select Player Skin:") .. "]"
		.. "textlist[.5,2.5;5.8,4;skins_set;"

	for i = 1, #skins.list do

		formspec = formspec .. skins.meta[ skins.list[i] ].name .. ","

		if skins.skins[name] == skins.list[i] then
			selected = i
		end
	end

	formspec = formspec .. ";" .. selected .. ";true]"

	local meta = skins.meta[ skins.skins[name] ]

	if meta then
		if meta.name then
			formspec = formspec .. "label[2,.5;".. F("Name: @1", meta.name) .. "]"
		end
		if meta.author then
			formspec = formspec .. "label[2,1;".. F("Author: @1", meta.author) .. "]"
		end
	end

	return formspec
end

-- update player skin
skins.update_player_skin = function(player)

	if not player then
		return
	end

	local name = player:get_player_name()

--	if skins.armor then
--		armor.textures[name].skin = skins.skins[name] .. ".png"
--		armor:set_player_armor(player)
--	else
		player:set_properties({
			textures = {skins.skins[name] .. ".png"},
		})
--	end

	skins.save()
end

-- load player skin on join
minetest.register_on_joinplayer(function(player)

	local name = player:get_player_name()

	if not skins.skins[name] then
		skins.skins[name] = "character_1"
	end

	skins.update_player_skin(player)

	if skins.inv then
		inventory_plus.register_button(player,"skins", "Skin")
	end
end)

-- formspec control
minetest.register_on_player_receive_fields(function(player, formname, fields)

	local name = player:get_player_name()

	if fields.skins then
		inventory_plus.set_inventory_formspec(player,
			skins.formspec.main(name) .. "button[0,.75;2,.5;main;Back]"
		)
	end

	local event = minetest.explode_textlist_event(fields["skins_set"])

	if event.type == "CHG" then

		local index = event.index

		if index > id then index = id end

		skins.skins[name] = skins.list[index]

		if skins.inv then
			inventory_plus.set_inventory_formspec(player,
				skins.formspec.main(name) .. "button[0,.75;2,.5;main;Back]"
			)
		end

		skins.update_player_skin(player)

	end
end)

-- admin command to set player skin (usually for custom skins)
minetest.register_chatcommand("setskin", {
	params = "<player> <skin number>",
	description = S("Admin command to set player skin"),
	privs = {server = true},
	func = function(name, param)

		if not param or param == "" then return end

		local user, skin = string.match(param, "([^ ]+) (-?%d+)")

		if not user or not skin then return end

		skins.skins[user] = "character_"..tonumber(skin)
		skins.save()

		minetest.chat_send_player(name,
			 "** " .. S("@1's skin set to", user) .. " character_" .. skin .. ".png")
	end,
})

-- player command to set skin
minetest.register_chatcommand("skin", {
	description = S("Set player skin"),
	privs = {interact = true},
	func = function(name, param)
		minetest.show_formspec(name,
			"skins_set",
			skins.formspec.main(name)
			.."button_exit[0,.75;2,.5;;".. F("Close") .."]"
		)
	end,
})

print (S("[MOD] Simple Skins loaded"))
