ghost_blocks = {}

ghost_blocks.block_list = {
    mcl_core = { --If this mod is defined, all blocks in the list will have ghost versions registered.
        --"mcl_core:slimeblock",
    },
    --default = {}
}

ghost_blocks.group_list = {
    "wood",
    "tree",
    "slab_wood",
    "raw_meat_block",
    "cooked_meat_block",
    "burnt_meat_block",
    "sand",
    "soil",
    "cobble",
    "stone",
    "wool",
    "leaves",
    "glass",
    "shulker_box",
    "baked_clay",
    "pane",
    "fence",
    "tnt",
    "anvil",
    "solid",
    "slab",
    "stair",
    "pickaxey",
    "axey",
    "shovely",
    "handy",
    "hoey",
    "swordy"
}

ghost_blocks.block_map = {}

function ghost_blocks.register_ghost_block(block)
    if not block then
        return
    end
    local block_data = nil
    pcall(function()
        block_data = table.copy(minetest.registered_nodes[block])
    end)
    if not block_data then
        minetest.log("error", "Could not create ghost block from "..block)
        return
    end
    local _, _, new_name = string.find(block, ".+:(.+)")
    if not new_name then
        minetest.log("error", "Could not create ghost block from "..block)
        return
    end
    new_name = "ghost_blocks:"..new_name
    if block == "mcl_enchanting:table" then
        new_name = "ghost_blocks:enchanting_table"
    elseif block == "mcl_smithing_table:table" then
        new_name = "ghost_blocks:smithing_table" 
    end
    if block == "ghost_blocks:ghostifier" then
        return
    end
    block_data.walkable = false
    block_data.post_effect_color = "#00000000"
    if not block_data.description then
        block_data.description = "Ghost "..block
    else
        block_data.description = "Ghost "..block_data.description
    end
    block_data.groups.ghost_block = 1
    block_data.groups.not_in_creative_inventory = 1
    block_data.groups.not_in_craft_guide = 1
    block_data.drop = new_name
	block_data._mcl_silk_touch_drop = {new_name}
    --override functions
    --block_data.on_place = nil
    --block_data.on_use = nil
    --block_data.on_secondary_use = nil
    --block_data.after_place_node = nil
    block_data.on_construct = nil
    --block_data.on_rightclick = nil
    --block_data.on_click = nil --is this a thing? Or just on_punch?
    --block_data.on_walk_over = nil
    --block_data.on_punch = nil
    --block_data.on_timer = nil
    --block_data.groups.eatable = nil
    --block_data._mcl_saturation = nil
    block_data.after_dig_node = nil --fixes enchanting table duplication
    if new_name == "ghost_blocks:ender_chest" then
        block_data.groups.pickaxey = 1
    end
    if new_name == "ghost_blocks:chest" then
        block_data.groups.axey = 1
    end
    if block_data.groups.shulker_box then
        block_data.groups.pickaxey = 1
    end
    --minetest.log(tostring(new_name))
    minetest.register_node(new_name, block_data)

    ghost_blocks.block_map[block] = new_name

end

local ghostifier_formspec =
"size[9,7]"..
"label[0.3,0.3;"..minetest.formspec_escape(minetest.colorize("#313131", "Ghostifier")).."]"..
"list[context;src;1.5,1;1,1]"..
mcl_formspec.get_itemslot_bg(1.5,1,1,1)..
"list[context;dst;5,1;1,1]"..
mcl_formspec.get_itemslot_bg(5,1,1,1)..
"list[current_player;main;0,2.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,2.5,9,3)..
"list[current_player;main;0,6;9,1;]"..
mcl_formspec.get_itemslot_bg(0,6,9,1)..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"

minetest.register_node("ghost_blocks:ghostifier", {
    description = "Ghostifier",
    hardness = 10,
    walkable = false,
    use_texture_alpha = "blend",
    sunlight_propagates = true,
    paramtype = "light",
    drawtype = "allfaces",
    tiles = {"ghost_blocks_ghostifier.png"},
    groups = {ghost_block = 1, pickaxey = 1},
    allow_metadata_inventory_put = function(pos, listname, index, stack, player)
        if minetest.is_protected(pos, player:get_player_name()) then
            return 0
        end
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        if listname == "src" then
            return stack:get_count()
    
        elseif listname == "dst" then
            return 0
        end
    end,
    
    after_dig_node = function(pos, oldnode, oldmetadata, digger)
        local meta = minetest.get_meta(pos)
        local meta2 = meta:to_table()
        meta:from_table(oldmetadata)
        local inv = meta:get_inventory()
        for _, listname in ipairs({"src", "dst"}) do
            local stack = inv:get_stack(listname, 1)
            if not stack:is_empty() then
                local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
                minetest.add_item(p, stack)
            end
        end
        meta:from_table(meta2)
	end,
    
     allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        local stack = inv:get_stack(from_list, from_index)
        return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
    end,
    
    allow_metadata_inventory_take = function(pos, listname, index, stack, player)
        if minetest.is_protected(pos, player:get_player_name()) then
            return 0
        end
        return stack:get_count()
    end,

    on_timer = function(pos, elapsed)
        --minetest.log("on_timer")
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        local update = true
        --minetest.log(elapsed)
        
        while elapsed > 0 and update do
            update = false
            if not inv:is_empty("src") then
                --minetest.log("src not empty")
                local src_stack = inv:get_stack("src", 1)
                local dst_stack = inv:get_stack("dst", 1)
                local original_itemstring = src_stack:get_name()
                local new_itemstring = ghost_blocks.block_map[original_itemstring]
                if new_itemstring then
                    --minetest.log("Original: "..original_itemstring..", New: "..new_itemstring)
                    if not inv:is_empty("dst") then
                        if new_itemstring ~= dst_stack:get_name() then
                            --minetest.log("dst contains different block, stopping")
                            break --if dst is full of different block
                        end
                        --minetest.log("dst contains correct block, continuing.")
                    end
                    if dst_stack:is_empty() then
                        -- create a new stack
                        dst_stack = ItemStack(new_itemstring)
                        src_stack:set_count(src_stack:get_count() - 1)
                        --minetest.log("dst is empty, creating new itemstack")
                    elseif dst_stack:get_count() >= 64 then
                        --minetest.log("dst is full, stopping")
                        -- the max item count is limited to 64
                        break
                    else
                        -- add one node into stack
                        --minetest.log("dst++; src--")
                        dst_stack:set_count(dst_stack:get_count() + 1)
                        src_stack:set_count(src_stack:get_count() - 1)
                    end
                    --minetest.log("setting src and dst")
                    inv:set_stack("dst", 1, dst_stack)
                    inv:set_stack("src", 1, src_stack)
                    
                    update = true
                end
    
            else
                --minetest.log("src is empty")
            end
        end
        minetest.get_node_timer(pos):stop()
        return false
    end,
    on_metadata_inventory_move = function(pos)
        minetest.get_node_timer(pos):start(1.0)
    end,
    on_metadata_inventory_put = function(pos)
        minetest.get_node_timer(pos):start(1.0)
    end,
    on_metadata_inventory_take = function(pos)
        minetest.get_node_timer(pos):start(1.0)
    end,
    
    on_construct = function(pos)
        local meta = minetest.get_meta(pos)
        local inv = meta:get_inventory()
        inv:set_size("src", 1)
        inv:set_size("dst", 1)
        meta:set_string("formspec", ghostifier_formspec)
        --on_timer(pos, 0)
    end
})

minetest.register_craft({
    output = "ghost_blocks:ghostifier",
    recipe = {
        {"mcl_core:glass", "mcl_core:glass", "mcl_core:glass"},
        {"mcl_core:glass", "mcl_mobitems:ghast_tear", "mcl_core:glass"},
        {"mcl_core:glass", "mcl_core:glass", "mcl_core:glass"}
    }
})

for dependency, block_list in pairs(ghost_blocks.block_list) do --Register indivdual blocks in block_list
    if minetest.get_modpath(dependency) then
        for _, block in ipairs(block_list) do
            --minetest.log(block)
            ghost_blocks.register_ghost_block(block)
        end
    end
end

local grouped_items = get_group_items(ghost_blocks.group_list)
for _, group in ipairs(ghost_blocks.group_list) do --Register all blocks in groups in group_list
    for _, block in pairs(grouped_items[group]) do
        ghost_blocks.register_ghost_block(block)
    end
end