local cache = smart_inventory.cache
local crecipes = smart_inventory.crecipes
local doc_addon = smart_inventory.doc_addon
local ui_tools = smart_inventory.ui_tools

-----------------------------------------------------
-- Update recipe preview item informations about the selected item
-----------------------------------------------------
local function update_crafting_preview(state)
	local player = state.location.rootState.location.player
	local listentry = state.param.crafting_recipes_preview_listentry
	local selected = state.param.crafting_recipes_preview_selected
	local itemdef = listentry.itemdef
	local inf_state = state:get("inf_area"):getContainerState()
	local cr_type_img = state:get("cr_type_img")
	local craft_result = inf_state:get("craft_result")
	local group_list = inf_state:get("item_groups")

	-- get recipe to display, check paging buttons needed
	local all_recipes
	local valid_recipes = {}
	local recipe
	local revealed_items_cache = {}

	if listentry.recipes then -- preselected recipes (ie. craftable)
		all_recipes = listentry.recipes
	elseif cache.citems[listentry.item] then -- check all available recipes (ie. search)
		all_recipes = cache.citems[listentry.item].in_output_recipe or {}
	else -- no recipes
		all_recipes = {}
	end

	for _, recipe in ipairs(all_recipes) do
		if crecipes.crecipes[recipe]:is_revealed(player, revealed_items_cache) then
			table.insert(valid_recipes, recipe)
		end
	end

	if valid_recipes[1] then
		if not valid_recipes[selected] then
			selected = 1
		end
		state.param.crafting_recipes_preview_selected = selected
		if selected > 1 and valid_recipes[selected-1] then
			state:get("preview_prev"):setVisible(true)
		else
			state:get("preview_prev"):setVisible(false)
		end
		if valid_recipes[selected+1] then
			state:get("preview_next"):setVisible(true)
		else
			state:get("preview_next"):setVisible(false)
		end

		if valid_recipes[selected] then
			recipe = valid_recipes[selected]
			local crecipe = crecipes.crecipes[recipe]
			if crecipe then
				recipe = crecipe:get_with_placeholder(player, state.param.crafting_items_in_inventory)
			end
		end
	else
		state:get("preview_prev"):setVisible(false)
		state:get("preview_next"):setVisible(false)
	end

	-- display the recipe result or selected item
	if recipe then
		if recipe.type == "normal" then
			state:get("cr_type"):setText("")
			cr_type_img:setVisible(false)
			state:get("ac1"):setVisible(true)
		elseif recipe.type == "cooking" then
			state:get("cr_type"):setText(recipe.type)
			state:get("cr_type"):setText("")
			cr_type_img:setVisible(true)
			cr_type_img:setImage("smart_inventory_furnace.png")
			state:get("ac1"):setVisible(false)
		else
			state:get("cr_type"):setText(recipe.type)
			cr_type_img:setVisible(false)
			state:get("ac1"):setVisible(false)
		end
		craft_result:setImage(recipe.output)
		craft_result:setVisible()
		state:get("craft_preview"):setCraft(recipe)
	else
		state:get("cr_type"):setText("")
		state:get("craft_preview"):setCraft(nil)
		cr_type_img:setVisible(false)
		state:get("ac1"):setVisible(false)
		if itemdef then
			craft_result:setVisible(true)
			craft_result:setImage(itemdef.name)
		else
			craft_result:setVisible(false)
		end
	end

	-- display docs icon if revealed item
	if smart_inventory.doc_items_mod then
		inf_state:get("doc_btn"):setVisible(false)
		local outitem = craft_result:getImage()
		if outitem then
			for z in outitem:gmatch("[^%s]+") do
				if doc_addon.is_revealed_item(z, player) then
					inf_state:get("doc_btn"):setVisible(true)
				end
				break
			end
		end
	end

	-- update info area
	if itemdef then
		inf_state:get("info1"):setText(itemdef.description)
		inf_state:get("info2"):setText("("..itemdef.name..")")
		if itemdef._doc_items_longdesc then
			inf_state:get("info3"):setText(itemdef._doc_items_longdesc)
		else
			inf_state:get("info3"):setText("")
		end

		group_list:clearItems()
		cache.add_item(listentry.itemdef)            -- Note: this addition does not affect the already prepared root lists
		if cache.citems[itemdef.name] then
			for _, groupdef in ipairs(ui_tools.get_tight_groups(cache.citems[itemdef.name].cgroups)) do
				group_list:addItem(groupdef.group_desc)
			end
		end
	elseif listentry.item then
		inf_state:get("info1"):setText("")
		inf_state:get("info2"):setText("("..listentry.item..")")
		inf_state:get("info3"):setText("")
	else
		inf_state:get("info1"):setText("")
		inf_state:get("info2"):setText("")
		inf_state:get("info3"):setText("")
		group_list:clearItems()
	end
end

-----------------------------------------------------
-- Update the group selection table
-----------------------------------------------------
local function update_group_selection(state, rebuild)
	local grouped = state.param.crafting_grouped_items
	local groups_sel = state:get("groups_sel")
	local grid = state:get("buttons_grid")
	local label = state:get("inf_area"):getContainerState():get("groups_label")

	if rebuild then
		state.param.crafting_group_list = ui_tools.update_group_selection(grouped, groups_sel, state.param.crafting_group_list)
	end

	local sel_id = groups_sel:getSelected()
	if state.param.crafting_group_list[sel_id] then
		state.param.crafting_craftable_list = grouped[state.param.crafting_group_list[sel_id]].items
		table.sort(state.param.crafting_craftable_list, function(a,b)
			return a.sort_value < b.sort_value
		end)
		grid:setList(state.param.crafting_craftable_list)
		label:setText(groups_sel:getSelectedItem())
	else
		label:setText("Empty List")
		grid:setList({})
	end
end

-----------------------------------------------------
-- Update the items list
-----------------------------------------------------
local function update_from_recipelist(state, recipelist, preview_item, replace_not_in_list)
	local old_preview_entry, old_preview_item, new_preview_entry, new_preview_item
	if state.param.crafting_recipes_preview_listentry then
		old_preview_item = state.param.crafting_recipes_preview_listentry.item
	end
	if preview_item == "" then
		new_preview_item = nil
	else
		new_preview_item = preview_item
	end

	local duplicate_index_tmp = {}
	local craftable_itemlist = {}

	for recipe, _ in pairs(recipelist) do
		local def = crecipes.crecipes[recipe].out_item
		local itemname = def.name
		if duplicate_index_tmp[itemname] then
			table.insert(duplicate_index_tmp[itemname].recipes, recipe)
		else
			local entry = {}
			for k,v in pairs(cache.citems[itemname].ui_item) do
				entry[k] = v
			end

			entry.recipes = {}
			duplicate_index_tmp[itemname] = entry
			table.insert(entry.recipes, recipe)
			table.insert(craftable_itemlist, entry)
			if new_preview_item and itemname == new_preview_item then
				new_preview_entry = entry
			end
			if old_preview_item and itemname == old_preview_item then
				old_preview_entry = entry
			end
		end
	end

	-- update crafting preview if the old is not in list anymore
	if new_preview_item then
		if not replace_not_in_list or not old_preview_entry then
			if not new_preview_entry then
				new_preview_entry = {
						itemdef = minetest.registered_items[new_preview_item],
						item = new_preview_item
					}
			end
			state.param.crafting_recipes_preview_selected = 1
			state.param.crafting_recipes_preview_listentry = new_preview_entry
			update_crafting_preview(state)
			if state:get("info_tog"):getId() == 1 then
				state:get("info_tog"):submit()
			end
		end
	elseif replace_not_in_list and not old_preview_entry then
		state.param.crafting_recipes_preview_selected = 1
		state.param.crafting_recipes_preview_listentry = {}
		update_crafting_preview(state)
	end

	-- update the groups selection
	state.param.crafting_grouped_items = ui_tools.get_list_grouped(craftable_itemlist)
	update_group_selection(state, true)
end

-----------------------------------------------------
-- Build list matching the placed grid
-----------------------------------------------------
local function update_from_grid(state, craft_grid, lookup_item)
	-- get all grid items for reference
	local player = state.location.rootState.location.player
	local reference_items = {}
	local items_hash = ""
	for _, stack in ipairs(craft_grid) do
		local name = stack:get_name()
		if name and name ~= "" then
			reference_items[name] = true
			items_hash=items_hash.."|"..name
		else
			items_hash=items_hash.."|empty"
		end
	end

	if items_hash ~= state.param.survival_grid_items_hash then
		state.param.survival_grid_items_hash = items_hash
		if next(reference_items) then
			-- update the grid with matched recipe items
			local recipes = crecipes.get_recipes_started_craft(player, craft_grid, reference_items)
			update_from_recipelist(state, recipes, lookup_item, true)  -- replace_not_in_list=true
		end
	end
end

-----------------------------------------------------
-- Lookup for item lookup_item
-----------------------------------------------------
local function do_lookup_item(state, playername, lookup_item)
	state.param.crafting_items_in_inventory = state.param.invobj:get_items()
	state.param.crafting_items_in_inventory[lookup_item] = true -- prefer in recipe preview
	-- get all craftable recipes with lookup-item as ingredient. Add recipes of lookup item to the list
	local recipes = crecipes.get_revealed_recipes_with_items(playername, {[lookup_item] = true })
	update_from_recipelist(state, recipes, lookup_item)
	state.param.crafting_ui_controller:update_list_variant("lookup", lookup_item)
end

-----------------------------------------------------
-- Lookup inventory
-----------------------------------------------------
local function create_lookup_inv(name)
	local player = minetest.get_player_by_name(name)
	local invname = name.."_crafting_inv"
	local plistname = "crafting_inv_lookup"
	local listname = "lookup"
	local pinv = player:get_inventory()
	local inv = minetest.get_inventory({type="detached", name=invname})
	if not inv then
		inv = minetest.create_detached_inventory(invname, {
			allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
				return 0
			end,
			allow_put = function(inv, listname, index, stack, player)
				if pinv:is_empty(plistname) then
					return 99
				else
					return 0
				end
			end,
			allow_take = function(inv, listname, index, stack, player)
				return 99
			end,
			on_put = function(inv, listname, index, stack, player)
				pinv:set_stack(plistname, index, stack)
				local name = player:get_player_name()
				local state = smart_inventory.get_page_state("crafting", name)
				do_lookup_item(state, name, stack:get_name())

				-- we are outsite of usual smartfs processing. So trigger the formspec update byself
				state.location.rootState:show()

				-- put back
				minetest.after(1, function()
					-- Check maybe player is away from the game
					local player = minetest.get_player_by_name(name)
					if not player then
						return
					end

					-- Check the player did not removed item from lookup field
					local pinv = player:get_inventory()
					local inv = minetest.get_inventory({type="detached", name=invname})
					local stack = pinv:get_stack(plistname, 1)

					-- put back
					local applied = pinv:add_item("main", stack)
					pinv:set_stack(plistname, 1, applied)
					inv:set_stack(listname, 1, applied)
				end)
			end,
			on_take = function(inv, listname, index, stack, player)
				pinv:set_stack(plistname, index, nil)
			end,
		}, name)
	end
	-- copy the item from player:listname inventory to the detached
	inv:set_size(listname, 1)
	pinv:set_size(plistname, 1)
	local stack = pinv:get_stack(plistname, 1)
	inv:set_stack(listname, 1, stack)
end

-----------------------------------------------------
-- Page layout definition
-----------------------------------------------------
local function crafting_callback(state)
	local player = state.location.rootState.location.player

	-- build up UI controller
	local ui_controller = {}
	ui_controller.state = state
	ui_controller.player =  minetest.get_player_by_name(state.location.rootState.location.player)
	state.param.crafting_ui_controller = ui_controller

	function ui_controller:set_ui_variant(new_ui)
		-- check if change needed
		if new_ui == self.toggle1 or new_ui == self.toggle2 then
			return
		end

		-- toggle show/hide elements
		if new_ui == 'list_small' then
			self.toggle1 = new_ui
			self.state:get("craft_img2"):setVisible(true)  --rahmen oben
			self.state:get("lookup_icon"):setPosition(10, 4)
			self.state:get("lookup"):setPosition(10, 4)
			self.state:get("craftable"):setPosition(11, 4)
			self.state:get("btn_all"):setPosition(11, 4.5)
			self.state:get("btn_grid"):setPosition(11.5, 4.0)
			if smart_inventory.doc_items_mod then
				self.state:get("reveal_tipp"):setPosition(11.5, 4.5)
			end
			self.state:get("search"):setPosition(12.2, 4.5)
			self.state:get("search_bg"):setPosition(12, 4)
			self.state:get("search_btn"):setPosition(15.2, 4.2)
			self.state:get("info_tog"):setPosition(16.2, 4.2)

			self.state:get("buttons_grid_Bg"):setPosition(10, 5)
			self.state:get("buttons_grid_Bg"):setSize(8, 4)
			self.state:get("buttons_grid"):reset(10.25, 5.15, 8, 4)

		elseif new_ui == 'list_big' then
			self.toggle1 = new_ui
			self.state:get("craft_img2"):setVisible(false)  --rahmen oben
			self.state:get("lookup_icon"):setPosition(10, 0)
			self.state:get("lookup"):setPosition(10, 0)
			self.state:get("craftable"):setPosition(11, 0)
			self.state:get("btn_all"):setPosition(11, 0.5)
			self.state:get("btn_grid"):setPosition(11.5, 0.0)
			if smart_inventory.doc_items_mod then
				self.state:get("reveal_tipp"):setPosition(11.5, 0.5)
			end
			self.state:get("search"):setPosition(12.2, 0.5)
			self.state:get("search_bg"):setPosition(12, 0)
			self.state:get("search_btn"):setPosition(15.2, 0.2)
			self.state:get("info_tog"):setPosition(16.2, 0.2)

			self.state:get("groups_sel"):setVisible(false)
			self.state:get("inf_area"):setVisible(false)

			self.state:get("buttons_grid_Bg"):setPosition(10, 1)
			self.state:get("buttons_grid_Bg"):setSize(8, 8)
			self.state:get("buttons_grid"):reset(10.25, 1.15, 8, 8)
			self.state:get("info_tog"):setId(3)
		else
			self.toggle2 = new_ui
		end

		if self.toggle1 == 'list_small' then
			if self.toggle2 == 'info' then
				self.state:get("groups_sel"):setVisible(false)
				self.state:get("inf_area"):setVisible(true)
				self.state:get("info_tog"):setId(1)
			elseif self.toggle2 == 'groups' then
				self.state:get("groups_sel"):setVisible(true)
				self.state:get("inf_area"):setVisible(false)
				self.state:get("info_tog"):setId(2)
			end
		end
		self:save()
	end

	function ui_controller:update_list_variant(list_variant, add_info)
		self.add_info = add_info
		-- reset group selection and search field on proposal mode change
		if self.list_variant ~= list_variant then
			self.list_variant = list_variant
			self.state:get("groups_sel"):setSelected(1)
			if list_variant ~= "search" then
				self.state:get("search"):setText("")
			end
		end

		-- auto-switch to the groups
		if list_variant == "lookup" or list_variant == "reveal_tipp" then
			state.param.crafting_ui_controller:set_ui_variant("info")
		else
			state.param.crafting_ui_controller:set_ui_variant("groups")
		end


		state:get("lookup_icon"):setBackground()
		state:get("search_bg"):setBackground()
		state:get("craftable"):setBackground()
		state:get("btn_grid"):setBackground()
		state:get("btn_all"):setBackground()
		if smart_inventory.doc_items_mod then
			state:get("reveal_tipp"):setBackground()
		end
		-- highlight the right button
		if list_variant == "lookup" then
			state:get("lookup_icon"):setBackground("halo.png")
		elseif list_variant == "search" then
			state:get("search_bg"):setBackground("halo.png")
		elseif list_variant == "craftable" then
			state:get("craftable"):setBackground("halo.png")
		elseif list_variant == "grid" then
			state:get("btn_grid"):setBackground("halo.png")
		elseif list_variant == "btn_all" then
		state:get("btn_all"):setBackground("halo.png")
		elseif list_variant == "reveal_tipp" then
			state:get("reveal_tipp"):setBackground("halo.png")
		end
		self:save()
	end

	function ui_controller:save()
		local savedata = minetest.deserialize(self.player:get_attribute("smart_inventory_settings")) or {}
		savedata.survival_list_variant = self.list_variant
		savedata.survival_toggle1 = self.toggle1
		savedata.survival_toggle2 = self.toggle2
		savedata.survival_lookup_item = self.lookup_item
		savedata.survival_add_info = self.add_info
		self.player:set_attribute("smart_inventory_settings", minetest.serialize(savedata))
	end

	function ui_controller:restore()
		local savedata = minetest.deserialize(self.player:get_attribute("smart_inventory_settings")) or {}

		if savedata.survival_toggle1 then
			self:set_ui_variant(savedata.survival_toggle1)
		end
		if savedata.survival_toggle2 then
			self:set_ui_variant(savedata.survival_toggle2)
		end
		if savedata.survival_list_variant then
			if savedata.survival_list_variant == "search" then
				local ui_text = self.state:get(savedata.survival_list_variant)
				ui_text:setText(savedata.survival_add_info)
				ui_text:submit_key_enter("unused", self.state.location.rootState.location.player)
			elseif savedata.survival_list_variant == "lookup" then
				do_lookup_item(self.state, self.state.location.rootState.location.player, savedata.survival_add_info)
			else
				local ui_button = self.state:get(savedata.survival_list_variant)
				if ui_button then
					ui_button:submit("unused", self.state.location.rootState.location.player)
				end
			end
		else
			self.state:get("craftable"):submit("unused", self.state.location.rootState.location.player)
			self:set_ui_variant("groups")
			self:update_list_variant("craftable")
		end
	end

	-- set inventory style
	state:element("code", {name = "additional_code", code =
			"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"..
			"listring[current_player;main]listring[current_player;craft]"
		})

	--Inventorys / left site
	state:inventory(1, 5, 8, 4,"main")
	state:inventory(1.2, 0.2, 3, 3,"craft")
	state:inventory(4.3, 1.2, 1, 1,"craftpreview")
	state:background(1, 0, 4.5, 3.5, "img1", "menu_bg.png")


	-- crafting helper buttons
	local btn_ac1 = state:image_button(4.4, 0.3, 0.8, 0.8, "ac1", "", "smart_inventory_preview_to_crafting_field.png")
	btn_ac1:onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "ac1")
		local grid = state:get("craft_preview"):getCraft()
		state.param.invobj:craft_item(grid)
	end)
	btn_ac1:setVisible(false)

	-- swap slots buttons
	state:image_button(0, 6, 1, 1, "swap1", "", "smart_inventory_swapline_button.png"):onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "swap1")
		state.param.invobj:swap_row_to_top(2)
	end)
	state:image_button(0, 7, 1, 1, "swap2", "", "smart_inventory_swapline_button.png"):onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "swap2")
		state.param.invobj:swap_row_to_top(3)
	end)
	state:image_button(0, 8, 1, 1, "swap3", "", "smart_inventory_swapline_button.png"):onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "swap3")
		state.param.invobj:swap_row_to_top(4)
	end)

	ui_tools.create_trash_inv(state, player)
	state:image(8,9,1,1,"trash_icon","smart_inventory_trash.png")
	state:inventory(8, 9, 1, 1, "trash"):useDetached(player.."_trash_inv")

	local btn_compress = state:image_button(1, 3.8, 1, 1, "compress", "","smart_inventory_compress_button.png")
	btn_compress:setTooltip("Merge stacks with same items to get free place")
	btn_compress:onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "compress")
		state.param.invobj:compress()
	end)

	local btn_sweep = state:image_button(2, 3.8, 1, 1, "clear", "", "smart_inventory_sweep_button.png")
	btn_sweep:setTooltip("Move all items from crafting grid back to inventory")
	btn_sweep:onClick(function(self, state, player)
		ui_tools.image_button_feedback(player, "crafting", "clear")
		state.param.invobj:sweep_crafting_inventory()
	end)

	-- recipe preview area
	smart_inventory.smartfs_elements.craft_preview(state, 6, 0, "craft_preview"):onButtonClicked(function(self, item, player)
		do_lookup_item(state, player, item)
	end)
	state:image(7,2.8,1,1,"cr_type_img",""):setVisible(false)
	state:label(7,3,"cr_type", "")
	local pr_prev_btn = state:button(6, 3, 1, 0.5, "preview_prev", "<<")
	pr_prev_btn:onClick(function(self, state, player)
		state.param.crafting_recipes_preview_selected = state.param.crafting_recipes_preview_selected -1
		update_crafting_preview(state)
	end)
	pr_prev_btn:setVisible(false)
	local pr_next_btn = state:button(8, 3, 1, 0.5, "preview_next", ">>")
	pr_next_btn:onClick(function(self, state, player)
		state.param.crafting_recipes_preview_selected = state.param.crafting_recipes_preview_selected +1
		update_crafting_preview(state)
	end)
	pr_next_btn:setVisible(false)

	-- (dynamic-1) group selection
	local group_sel = state:listbox(10.2, 0.15, 7.6, 3.6, "groups_sel",nil, true)
	group_sel:onClick(function(self, state, player)
		local selected = self:getSelectedItem()
		if selected then
			update_group_selection(state, false)
		end
	end)

	-- (dynamic-2) item preview area
	state:background(10.0, 0.1, 8, 3.8, "craft_img2", "minimap_overlay_square.png")
	local inf_area = state:view(6.4, 0.1, "inf_area")
	local inf_state = inf_area:getContainerState()
	inf_state:label(11.5,0.5,"info1", "")
	inf_state:label(11.5,1.0,"info2", "")
	inf_state:label(11.5,1.5,"info3", "")
	inf_state:item_image(10.2,0.3, 1, 1, "craft_result",nil):setVisible(false)
	if smart_inventory.doc_items_mod then
		local doc_btn = inf_state:image_button(10.4,2.3, 0.7, 0.7, "doc_btn","", "doc_button_icon_lores.png")
		doc_btn:setTooltip("Show documentation for revealed item")
		doc_btn:setVisible(false)
		doc_btn:onClick(function(self, state, player)
			local outitem = state:get("craft_result"):getImage()
			if outitem then
				for z in outitem:gmatch("[^%s]+") do
					if minetest.registered_items[z] then
						doc_addon.show(z, player)
					end
					break
				end
			end
		end)
	end
	inf_state:label(10.3, 3.25, "groups_label", "All")

	inf_state:listbox(12, 2, 5.7, 1.3, "item_groups",nil, true)
	inf_area:setVisible(false)

	-- Lookup
	create_lookup_inv(player)
	state:image(10, 4, 1, 1,"lookup_icon", "smart_inventory_lookup_field.png")
	local inv_lookup = state:inventory(10, 4.0, 1, 1,"lookup"):useDetached(player.."_crafting_inv")


	-- Get craftable by items in inventory
	local btn_craftable = state:image_button(11, 4, 0.5, 0.5, "craftable", "", "smart_inventory_craftable_button.png")
	btn_craftable:setTooltip("Show items crafteable by items in inventory")
	btn_craftable:onClick(function(self, state, player)
		state.param.crafting_items_in_inventory = state.param.invobj:get_items()
		local craftable = crecipes.get_recipes_craftable(player, state.param.crafting_items_in_inventory)
		update_from_recipelist(state, craftable)
		ui_controller:update_list_variant("craftable")
	end)

	local grid_btn = state:image_button(11.5, 4, 0.5, 0.5, "btn_grid", "", "smart_inventory_craftable_button.png")
	grid_btn:setTooltip("Search for recipes matching the grid")
	grid_btn:onClick(function(self, state, player)
		local player = state.location.rootState.location.player
		state.param.crafting_ui_controller:update_list_variant("grid")
		local craft_grid = state.param.invobj.inventory:get_list("craft")
		local ret_item = state.param.invobj.inventory:get_list("craftpreview")[1]
		update_from_grid(state, craft_grid, ret_item:get_name())
	end)

	-- Get craftable by items in inventory
	local btn_all = state:image_button(11, 4.5, 0.5, 0.5, "btn_all", "", "smart_inventory_creative_button.png")
	if smart_inventory.doc_items_mod then
		btn_all:setTooltip("Show all already revealed items")
	else
		btn_all:setTooltip("Show all items")
	end
	btn_all:onClick(function(self, state, player)
		local all_revealed = ui_tools.filter_by_revealed(ui_tools.root_list_all, player, true)
		state.param.crafting_recipes_preview_selected = 1
		state.param.crafting_recipes_preview_listentry = all_revealed[1] or {}
		update_crafting_preview(state)
		state.param.crafting_grouped_items = ui_tools.get_list_grouped(all_revealed)

		update_group_selection(state, true)
		ui_controller:update_list_variant("btn_all")
	end)

	-- Reveal tipps button
	if smart_inventory.doc_items_mod then
		local reveal_button = state:image_button(11.5, 4.5, 0.5, 0.5, "reveal_tipp", "", "smart_inventory_reveal_tips_button.png")
		reveal_button:setTooltip("Show proposal what should be crafted to reveal more items")
		reveal_button:onClick(function(self, state, player)
			local all_revealed = ui_tools.filter_by_revealed(ui_tools.root_list_all, player)
			local top_revealed = ui_tools.filter_by_top_reveal(all_revealed, player)
			state.param.crafting_recipes_preview_selected = 1
			state.param.crafting_recipes_preview_listentry = top_revealed[1] or {}
			update_crafting_preview(state)
			state.param.crafting_grouped_items = ui_tools.get_list_grouped(top_revealed)

			update_group_selection(state, true)
			ui_controller:update_list_variant("reveal_tipp")
		end)
	end

	-- search
	state:background(12, 4, 4, 0.9, "search_bg", nil) --field background not usable
	local searchfield = state:field(12.2, 4.5, 3.4, 0.5, "search")
	searchfield:setCloseOnEnter(false)
	searchfield:onKeyEnter(function(self, state, player)
		local search_string = self:getText()
		if string.len(search_string) < 3 then
			return
		end

		local filtered_list = ui_tools.filter_by_searchstring(ui_tools.root_list_all, search_string)
		filtered_list = ui_tools.filter_by_revealed(filtered_list, player)
		state.param.crafting_grouped_items = ui_tools.get_list_grouped(filtered_list)
		update_group_selection(state, true)
		ui_controller:update_list_variant("search", search_string)
	end)

	local search_button = state:button(15.2, 4.2, 0.8, 0.5, "search_btn", "Go")
	search_button:setTooltip("Perform search action")
	search_button:onClick(function(self, state, player)
		state:get("search"):submit_key_enter("", player)
	end)

	-- groups toggle
	local info_tog = state:toggle(16.2,4.2,1.8,0.5, "info_tog", {"Info", "Groups", "Hide"})
	info_tog:onToggle(function(self, state, player)
		local id = self:getId()
		if id == 1 then
			state.param.crafting_ui_controller:set_ui_variant("list_small")
			state.param.crafting_ui_controller:set_ui_variant("info")
		elseif id == 2 then
			state.param.crafting_ui_controller:set_ui_variant("list_small")
			state.param.crafting_ui_controller:set_ui_variant("groups")
		elseif id == 3 then
			state.param.crafting_ui_controller:set_ui_variant("list_big")
		end
	end)

	-- craftable items grid
	state:background(10, 5, 8, 4, "buttons_grid_Bg", "minimap_overlay_square.png")
	local grid = smart_inventory.smartfs_elements.buttons_grid(state, 10.25, 5.15, 8 , 4, "buttons_grid", 0.75,0.75)
	grid:onClick(function(self, state, index, player)
		local listentry = state.param.crafting_craftable_list[index]
		if ui_controller.list_variant == "lookup" then
			do_lookup_item(state, state.location.rootState.location.player, listentry.item)
		else
			state.param.crafting_recipes_preview_selected = 1
			state.param.crafting_recipes_preview_listentry = listentry
			update_crafting_preview(state)
		end
		state.param.crafting_ui_controller:set_ui_variant("info")
	end)

	ui_controller:restore()
end

-----------------------------------------------------
-- Register page in smart_inventory
-----------------------------------------------------
smart_inventory.register_page({
	name = "crafting",
	tooltip = "Craft new items",
	icon = "smart_inventory_crafting_inventory_button.png",
	smartfs_callback = crafting_callback,
	sequence = 10
})

-----------------------------------------------------
-- Use lookup for predict item
-----------------------------------------------------
minetest.register_craft_predict(function(stack, player, old_craft_grid, craft_inv)
	local name = player:get_player_name()
	local state = smart_inventory.get_page_state("crafting", name)
	if not state then
		return
	end

	if state.param.crafting_ui_controller.list_variant ~= 'grid' then
		return
	end
	update_from_grid(state, old_craft_grid, stack:get_name())
	state.location.rootState:show()
end)
