--this will allow other mods to see crafts, but not modify the actual data used
--do note that because of this method, crafts can be registered during game play,
--however will not show up in registered_crafts
local registered_anvil_crafts = {}
minetest.register_on_mods_loaded(function()
    fl_workshop.registered_anvil_crafts = table.copy(registered_anvil_crafts)
end)

--this could have more protections
function fl_workshop.register_anvil_craft(craft_table)
    assert(craft_table, "[fl_workshop:anvil] failure to provide craft table!")
    if type(craft_table) ~= "table" then error("[fl_workshop:anvil] value passed is not a table!") end
    assert(craft_table.output, "[fl_workshop:anvil] failure to provide craft output!")
    if type(craft_table.output) ~= "string" then error("[fl_workshop:anvil] output is not a string!") end
    assert(craft_table.recipe, "[fl_workshop:anvil] failure to provide craft recipe!")
    if type(craft_table.recipe) ~= "table" then error("[fl_workshop:anvil] recipe is not a table!") end

    table.insert(registered_anvil_crafts, craft_table)
end

--[[
--how to use it
fl_workshop.register_anvil_craft({
    output = string value of output itemstack,
    recipe = {string itemstack, string itemstack}
})

--example registration
fl_workshop.register_anvil_craft({
    recipe = {"fl_tools:gold_shovel", "fl_ores:diamond_ore"},
    output = "fl_tools:diamond_shovel"
})
--]]

--table containing players currently shown anvil formspec
viewing_anvil = {}

minetest.register_node("fl_workshop:anvil", {
    description = "anvil",
    paramtype = "light",
    paramtype2 = "facedir",
    use_texture_alpha = "clip",
    drawtype = "mesh",
    mesh = "farlands_anvil.obj",
    visual_scale = 0.5,
    wield_scale = {x=0.5, y=0.5, z=0.5},
    selection_box = {
        type = "fixed",
        fixed = {
            {-0.3, -0.5, -0.45, 0.3, -0.2, 0.45}, --base
            {-0.25, -0.2, -0.375, 0.25, 0, 0.375}, --middle
            {-0.3125, 0, -0.5, 0.3125, 0.5, 0.5}, --top
        }
    },
    collision_box  = {
        type = "fixed",
        fixed = {
            {-0.3, -0.5, -0.45, 0.3, -0.2, 0.45}, --base
            {-0.25, -0.2, -0.375, 0.25, 0, 0.375}, --middle
            {-0.3125, 0, -0.5, 0.3125, 0.5, 0.5}, --top
        }
    },
    tiles = {"farlands_anvil.png"},
    on_construct = function(pos)
        local inv = minetest.get_meta(pos):get_inventory()
        inv:set_size("input", 2)
        inv:set_size("output", 1)
    end,
    on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)

        --vars for stuff
        --local chName = "chest name"
        local iPos = pos.x .. "," .. pos.y .. "," .. pos.z
        local cInvSize = clicker:get_inventory():get_size("main")
        local rLength = (cInvSize-9)/3
        local slotSize
        local formSize
        if rLength == 12 then slotSize, formSize = 0.725, "10.4,9.475"
        elseif rLength == 11 then slotSize, formSize = 0.8, "10.4,9.7"
        elseif rLength == 10 then slotSize, formSize = 0.89, "10.4,9.97"
        else slotSize, formSize = 1, "10.4,10.3" end

        --header of formspec
        local formspec = {
            "formspec_version[4]",
            "size[" .. formSize .. "]",
            "no_prepend[]",
            "style_type[box;colors=#77777710,#77777710,#777,#777]",
            "style_type[list;size=1;spacing=0.1]",
            "listcolors[#0000;#ffffff20]",
            "bgcolor[black;neither]",
            "background9[0,0;" .. formSize .. ";i3_bg_full.png;false;10]",
        }

        --build anvil part
        local anvil_formspec = {
            "image[0.25,0.5;2,2;farlands_hammer.png]",
            "label[3.25,1;Name & Upgrade]",
            --start description input
            "box[3.25,1.5;4,0.5;#bababa25]",
            "style_type[field;border=false]",
            "field[3.3,1.5;3.3,0.5;description;;]",
            "field_close_on_enter[description;false]",
            "style_type[image_button;border=false]",
            "style_type[image_button:hovered;fgimg=i3_export.png^\\[brighten]",
            "image_button[6.75,1.55;0.35,0.35;i3_export.png;set_description;]",
            --start crafting section
            "box[1.7,3.2;1,1;]",
            "list[nodemeta:" .. iPos .. ";input;1.7,3.2;1,1;]",
            "image[3.3,3.3;0.8,0.8;i3_dash.png^\\(i3_dash.png\\^[transformR90)]",
            "box[4.7,3.2;1,1;]",
            "list[nodemeta:" .. iPos .. ";input;4.7,3.2;1,1;1]",
            "image[6.2,3.2;1,1;i3_arrow.png]",
            "box[7.7,3.2;1,1;]",
            "list[nodemeta:" .. iPos .. ";output;7.7,3.2;1,1;]",
        }

        table.insert(formspec, table.concat(anvil_formspec, ""))

        --build inventory part of formspec
        table.insert(formspec, "label[0.3,5.4;Inventory]")
        table.insert(formspec, "style_type[box;colors=#77777710,#77777710,#777,#777]")
        for i=0, 8 do
            table.insert(formspec, "box[" .. 0.3+i+(i*0.1) ..",5.7;1,1;]")
        end
        table.insert(formspec, "list[current_player;main;0.3,5.7;9,1;]")
        table.insert(formspec, "style_type[list;size=" .. slotSize .. ";spacing=0.1]")
        table.insert(formspec, "style_type[box;colors=#666]") -- change bottom 3 rows color
        for i=0, 2 do
            for j=0, rLength-1 do
                table.insert(formspec, "box[" .. 0.3+(j*0.1)+(j*slotSize) .."," .. 6.8+(i*0.1)+(i*slotSize) .. ";"
                .. slotSize .. "," .. slotSize .. ";]")
            end
            table.insert(formspec, "list[current_player;main;0.3," .. 6.8+(i*0.1)+(i*slotSize) .. ";"
            .. rLength .. ",1;" .. 9+(rLength*i) .. "]")
        end

        --enable shiftclicking?
        table.insert(formspec, "listring[nodemeta:" .. iPos .. ";input]")
        table.insert(formspec, "listring[current_player;main]")

        --show formspec
        local chest_formspec = table.concat(formspec, "")
        minetest.show_formspec(clicker:get_player_name(), "fl_workshop:anvil_formspec", chest_formspec)
        viewing_anvil[clicker:get_player_name()] = pos
    end,
    allow_metadata_inventory_put = function(pos, listname, index, stack, player)
        if listname == "output" then return 0 else return stack:get_count() end
    end,
    allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
        if to_list == "output" then return 0
        elseif from_list == "output" and to_list == "input" then
            local inv = minetest.get_meta(pos):get_inventory()
            if inv:get_stack(to_list, to_index):is_empty() then return count else return 0 end
        else return 0 end
    end,
    on_metadata_inventory_put = function(pos, listname, index, stack, player)
        local inv = minetest.get_meta(pos):get_inventory()
        if listname == "input" and inv:get_stack(listname, 1):get_name() == inv:get_stack(listname, 2):get_name() then
            if minetest.get_item_group(inv:get_stack(listname, index):get_name(), "tool")  ~= 0 then
                local out_stack = inv:get_stack(listname, 1)
                local out_wear = inv:get_stack(listname, 2):get_wear()
                out_stack:set_wear(65535 - ((65535 - inv:get_stack(listname, 1):get_wear()) + (65535 - out_wear)))
                inv:set_stack("output", 1, out_stack)
                return
            end
        end
        if minetest.get_item_group(inv:get_stack("input", 2):get_name(), "dye") ~= 0
        and inv:get_stack("input", 1):get_name() ~= "" then
            --minetest.chat_send_all("sucess")
            local color
            local spltstr = string.split(inv:get_stack("input", 2):get_name(), ":")
            for _, drow in pairs(fl_dyes.dyes) do
                if drow[1] == string.sub(spltstr[2], 1, -5) then
                    color = drow[3]
                end
            end

            if inv:get_stack("input", 1):get_meta():get_string("description") ~= "" then
                local out_stack = ItemStack(inv:get_stack("input", 1):get_name())
                out_stack:get_meta():set_string(
                    "description",
                    minetest.colorize(
                        color,
                        minetest.strip_colors(inv:get_stack("input", 1):get_meta():get_string("description"))
                    )
                )
                inv:set_stack("output", 1, out_stack)
            else
                if not minetest.registered_items[inv:get_stack("input", 1):get_name()] then return end
                local desc = minetest.registered_items[inv:get_stack("input", 1):get_name()].description
                local out_stack = ItemStack(inv:get_stack("input", 1):get_name())
                out_stack:get_meta():set_string("description", minetest.colorize(color, desc))
                inv:set_stack("output", 1, out_stack)
            end
        end
        if not inv:get_stack("input", 1):is_empty() and not inv:get_stack("input", 2):is_empty() then
            for _, craft_table in pairs(registered_anvil_crafts) do
                if inv:get_stack("input", 1):get_name() == craft_table.recipe[1]
                and inv:get_stack("input", 2):get_name() == craft_table.recipe[2] then
                    inv:set_stack("output", 1, ItemStack(craft_table.output))
                end
            end
        end
    end,
    on_metadata_inventory_take = function(pos, listname, index, stack, player)
        local inv = minetest.get_meta(pos):get_inventory()
        if listname == "input" then inv:set_stack("output", 1, ItemStack(""))
        elseif listname == "output" then
            local one = inv:get_stack("input", 1)
            local two = inv:get_stack("input", 2)
            one:take_item()
            two:take_item()
            inv:set_stack("input", 1, one)
            inv:set_stack("input", 2, two)
        end
    end,
    on_dig = function(pos, node, digger)
        local inv = minetest.get_inventory({type="node", pos=pos})
        for _, item in ipairs(inv:get_list("input")) do
            local posi = {
                x=pos.x + (math.random(-2,2)/5),
                y=pos.y + (math.random(0,2)/5),
                z=pos.z + (math.random(-2,2)/5),
            }
            minetest.add_item(posi, item)
        end
        minetest.node_dig(pos, node, digger)
    end,
    on_place = minetest.rotate_node,
    groups = {oddly_breakable_by_hand = 1},
})

minetest.register_on_player_receive_fields(function(player, formname, fields)
    if formname ~= "fl_workshop:anvil_formspec" then return end
    if fields.quit == "true" then
        viewing_anvil[player:get_player_name()] = nil
        return
    end

    --minetest.chat_send_all(dump(fields))

    local anvil_inv = minetest.get_inventory({type = "node", pos = viewing_anvil[player:get_player_name()]})
    if fields.description and not anvil_inv:get_stack("output", 1):is_empty() and fields.description ~= "" then
        local desc = fields.description
        local i, j = string.find(anvil_inv:get_stack("output", 1):get_meta():get_string("description"), "%(c@[^)]+%)")
        if j then
            local ccode = string.sub(anvil_inv:get_stack("output", 1):get_meta():get_string("description"), i, j)
            desc = "\27" .. ccode .. fields.description .. "\27(c@#ffffff)"
        end

        local stack = anvil_inv:get_stack("output", 1)
        stack:set_count(1)
        stack:get_meta():set_string("description", desc)
        anvil_inv:set_stack("output", 1, stack)
    elseif anvil_inv:get_stack("output", 1):is_empty()
    and not anvil_inv:get_stack("input", 1):is_empty()
    and fields.description ~= "" then
        local stack = anvil_inv:get_stack("input", 1)
        stack:set_count(1)
        --testing colorization
        --stack:get_meta():set_string("description", minetest.colorize("#000000", fields.description))
        stack:get_meta():set_string("description", fields.description)
        anvil_inv:set_stack("output", 1, stack)
    end
end)