------------------------------------------------------------
-- Copyright (c) 2016 tacigar
-- https://github.com/tacigar/maidroid
------------------------------------------------------------

local util = maidroid.util
local _aux = maidroid.modules._aux

local state = {
	walk = 0,
	plant = 1,
	punch = 2,
	walk_to_tree = 3,
	walk_avoid = 4,
}
local find_lenvec = {x = 3, y = 0, z = 3}
local plant_lenvec = {x = 2, y = 0, z = 2}
local max_punch_time = 20
local max_plant_time = 20
local max_avoid_time = 15
local target_tree_list = { "default:tree" }
local target_sapling_list = { "default:sapling" }

-- check the maidroid need to start to punch
local function check_punch_flag(forward_pos)
	local forward_upper_pos = util.table_shallow_copy(forward_pos)
	while true do
		local forward_upper_node = minetest.get_node(forward_upper_pos)
		if util.table_find_value(target_tree_list, forward_upper_node.name) then
			return true, forward_upper_pos, forward_upper_node
		elseif forward_upper_node.name ~= "air" then break end
		forward_upper_pos.y = forward_upper_pos.y + 1
	end
	return false, nil, nil
end

-- check the maidroid has sapling items
local function has_sapling_item(self)
	local inv = maidroid._aux.get_maidroid_inventory(self)
	local stacks = inv:get_list("main")
	for _, stack in ipairs(stacks) do
		local item_name = stack:get_name()
		if util.table_find_value(target_sapling_list, item_name) then
			return true
		end
	end
	return false
end

maidroid.register_module("maidroid:lumberjack_module", {
	description = "Maidroid Module : Lumberjack",
	inventory_image = "maidroid_lumberjack_module.png",

	initialize = function(self)
		self.state = state.walk
		self.time_count = 0
		self.object:setacceleration{x = 0, y = -10, z = 0}
		self.object:set_animation(maidroid.animations.walk, 15, 0)
		self.preposition = self.object:getpos()
		self.destination = nil
		_aux.change_dir(self)
	end,

	finalize = function(self)
		self.state = nil
		self.time_count = nil
		self.preposition = nil
		self.object:setvelocity{x = 0, y = 0, z = 0}
		self.destination = nil
	end,

	on_step = function(self, dtime)
		local pos = self.object:getpos()
		local rpos = vector.round(pos)
		local yaw = self.object:getyaw()
		local forward = _aux.get_forward(yaw)
		local rforward = _aux.get_round_forward(forward)
		local forward_pos = vector.add(rpos, rforward)
		local forward_node = minetest.get_node(forward_pos)
		local forward_under_pos = _aux.get_under_pos(forward_pos)
		local forward_under_node = minetest.get_node(forward_under_pos)

		if self.state == state.walk then
			local b, dest = _aux.search_surrounding(self, find_lenvec, function(self, pos, node)
				return util.table_find_value(target_tree_list, node.name)
			end)
			if b then -- walk to tree
				self.state = state.walk_to_tree
				self.destination = dest
				_aux.change_dir_to(self, dest)
				-- to plant sapling
			elseif forward_node.name == "air"
				and minetest.get_item_group(forward_under_node.name, "soil") > 0
				and not _aux.search_surrounding(self, plant_lenvec, function(self, pos, node) -- no tree around
					return util.table_find_value(target_tree_list, node.name)
					or util.table_find_value(target_sapling_list, node.name)
				end)
				and has_sapling_item(self) then
					self.state = state.plant
					self.object:set_animation(maidroid.animations.mine, 15, 0)
					self.object:setvelocity{x = 0, y = 0, z = 0}
					-- else continue to walk
				else
					if pos.x == self.preposition.x or pos.z == self.preposition.z then
						_aux.change_dir(self)
					end
				end
				-- pickup sapling items
				_aux.pickup_item(self, 1.5, function(itemstring)
					return util.table_find_value(target_sapling_list, itemstring)
				end)

			elseif self.state == state.punch then
				if self.time_count >= max_punch_time then
					local punch_flag, forward_upper_pos, forward_upper_node = check_punch_flag(self.destination)
					if punch_flag then
						minetest.remove_node(forward_upper_pos)
						local inv = minetest.get_inventory{type = "detached", name = self.invname}
						local stacks = minetest.get_node_drops(forward_upper_node.name)
						for _, stack in ipairs(stacks) do
							local leftover = inv:add_item("main", stack)
							minetest.add_item(forward_pos, leftover)
						end
					end
					if (not forward_upper_pos) or (forward_upper_pos and
					not check_punch_flag(_aux.get_upper_pos(forward_upper_pos))) then
						self.state = state.walk
						self.object:set_animation(maidroid.animations.walk, 15, 0)
						_aux.change_dir(self)
					end
					self.time_count = 0
				else
					self.time_count = self.time_count + 1
				end

			elseif self.state == state.plant then
				if self.time_count > max_plant_time then
					if forward_node.name == "air"
					and minetest.get_item_group(forward_under_node.name, "soil") > 0 then
						local inv = minetest.get_inventory{type = "detached", name = self.invname}
						local stacks = inv:get_list("main")
						for i, stack in ipairs(stacks) do
							local itemname = stack:get_name()
							if util.table_find_value(target_sapling_list, itemname) then
								minetest.add_node(forward_pos, {name = itemname, param2 = 1})
								stack:take_item(1)
								inv:set_stack("main", i, stack)
								break
							end
						end
					end
					self.state = state.walk
					self.object:set_animation(maidroid.animations.walk, 15, 0)
					self.time_count = 0
					_aux.change_dir(self)
				else
					self.time_count = self.time_count + 1
				end

			elseif self.state == state.walk_to_tree then
				if vector.distance(pos, self.destination) < 1.5 then -- to punch state
					local destnode = minetest.get_node(self.destination)
					if (util.table_find_value(target_tree_list, destnode.name)) then
						self.state = state.punch
						self.object:set_animation(maidroid.animations.mine, 15, 0)
						self.object:setvelocity{x = 0, y = 0, z = 0}
					else
						self.state = state.walk
						self.object:set_animation(maidroid.animations.walk, 15, 0)
						self.time_count = 0
						_aux.change_dir(self)
					end
				else
					if pos.x == self.preposition.x or pos.z == self.preposition.z then
						self.state = state.walk_avoid
						self.object:set_animation(maidroid.animations.walk, 15, 0)
						self.time_count = 0
						_aux.change_dir(self)
					end
				end

			elseif self.state == state.walk_avoid then
				if self.time_count > max_avoid_time then
					self.state = state.walk
					self.time_count = 0
				else
					self.time_count = self.time_count + 1
				end
			end
			self.preposition = pos
		end
	})