--localize functions for better performance
local string_byte = string.byte
local string_sub = string.sub
local get_item_group = minetest.get_item_group
local add_particlespawner = minetest.add_particlespawner
local add_item = minetest.add_item
local get_node = minetest.get_node
local add_entity = minetest.add_entity

local modpath = minetest.get_modpath("hot_air_balloons")
local set_rescue, mark_for_deletion_if_piloted = dofile(modpath .. "/absent_ballooner_rescuing.lua")
local handle_movement = dofile(modpath .. "/movement.lua")

local is_in_creative = function(name)
	return creative and creative.is_enabled_for
		and creative.is_enabled_for(name)
end

local get_fire_particle = function (pos)
	pos.y = pos.y + 3
	return {
		amount = 3,
		time = 1,
		minpos = pos,
		maxpos = pos,
		minvel = {x = 0, y = 1, z = 0},
		maxvel = {x = 0, y = 1, z = 0},
		minexptime = 1,
		maxexptime = 1,
		minsize = 10,
		maxsize = 5,
		collisiondetection = false,
		vertical = false,
		texture = "hot_air_balloons_flame.png"
	}
end

local add_heat = function(self, player)
	local item_stack = player:get_wielded_item()
	local item_name = item_stack:get_name()
	local group_coal = get_item_group(item_name, "coal")
	if group_coal == 0
	then
		return false
	end
	local heat = self.heat
	heat = heat + 1200 * group_coal --1 min until heat is back to original
	if heat < 12000 --cap heat at 12000 (10 min)
	then
		self.heat = heat
		--adding particle effect
		local pos = self.object:get_pos()
		add_particlespawner(get_fire_particle(pos))
		if not is_in_creative(player:get_player_name())
		then
			item_stack:take_item()
			player:set_wielded_item(item_stack)
		end
	end
	return true
end

--global table, has fields get_entity_def and get_item_def
--custom balloons right now turn into normal ones when the pilot leaves
hot_air_balloons = {}
hot_air_balloons.get_entity = function(name, mesh_name, texture_name)
	return
	name,
	{
		initial_properties =
		{
			hp_max = 1,
			physical = true,
			weight = 5,
			collisionbox = {-0.65, -0.01, -0.65, 0.65, 1.11, 0.65},
			visual = "mesh",
			mesh = "hot_air_balloons_balloon.obj",
			textures = {"hot_air_balloons_balloon_model.png"},
			is_visible = true,
			makes_footstep_sound = false,
			automatic_rotate = false,
			backface_culling = false,
		},
		heat = 0,
		balloon_type = name,
		
		on_step = function(self, dtime)
			--decrease heat, move
			if self.heat > 0
			then
				self.heat = self.heat - 1
			end
			handle_movement(self)
		end,
		on_rightclick = function (self, clicker)
			--if hoding coal, increase heat, else mount/dismount
			if not clicker or not clicker:is_player()
			then
				return
			end
			--checking if clicker is holding coal
			--heating balloon and returning if yes
			if add_heat(self, clicker)
			then
				return
			end
			
			--if not holding coal:
			local playername = clicker:get_player_name()
			if self.pilot and self.pilot == playername
			then
				self.pilot = nil
				clicker:set_detach()
			elseif not self.pilot
			then
				--attach
				self.pilot = playername
				clicker:set_attach(self.object, "",
					{x = 0, y = 1, z = 0}, {x = 0, y = 0, z = 0})
			end
		end,
		--if pilot leaves start sinking and prepare for next pilot
		on_detach_child = function(self, child)
			self.heat = 0
			self.object:setvelocity({x = 0, y = 0, z = 0})
		end,
		
		on_activate = function(self, staticdata, dtime_s)
			self.object:set_armor_groups({punch_operable = 1})
			--so balloons don't get lost
			self.object:setvelocity({x = 0, y = 0, z = 0})
			
			--checking if balloon was spawned from item or unloaded without pilot
			if staticdata == ""
			then
				return
			end
			--checking if balloon should despawn when pilot logged off
			local first_char = string_byte(staticdata)
			--ballooner logged off, balloon will respawn when ballooner logs back in
			if  first_char == 82 --chr 82 = R 
			then
				self.object:remove()
				return
			--absent ballooner logged back in
			elseif first_char == 80 --chr 80 = P
			then
				set_rescue(self, string_sub(staticdata, 2))
			end
		end,
		
		get_staticdata = mark_for_deletion_if_piloted,
		
		
		on_punch = function(self, puncher) --drop balloon item
			if self.pilot
			then
				return
			elseif not (puncher and puncher:is_player())
			then
				return
			else
				self.object:remove()
				local inv = puncher:get_inventory()
				if not is_in_creative(puncher:get_player_name())
					or not inv:contains_item("main", "hot_air_balloons:item")
				then
					local leftover = inv:add_item("main", "hot_air_balloons:item")
					if not leftover:is_empty()
					then
						add_item(self.object:get_pos(), leftover)
					end
				end
			end
		end,
	}
end

hot_air_balloons.get_item = function(name, description, texture, object_name)
return
	name,
	{
		description = description,
		inventory_image = texture,
		stack_max = 1,
		liquids_pointable = true,
		groups = {flammable = 2},
		on_place =
		function (itemstack, placer, pointed_thing)
			--places balloon if the clicked thing is a node and the above node is air
			if pointed_thing.type == "node"
				and get_node (pointed_thing.above).name == "air"
			then
				if not is_in_creative(placer:get_player_name())
				then
					itemstack:take_item()
				end
				local pos_to_place = pointed_thing.above
				pos_to_place.y = pos_to_place.y - 0.5 --subtracting 0.5 to place on ground
				add_entity(pointed_thing.above, object_name)
			end
			--add remaining items to inventory
			return itemstack
		end
	}
end
--registering the balloon entity, item and recepies

minetest.register_entity(hot_air_balloons.get_entity(
		"hot_air_balloons:balloon",
		"hot_air_balloons_balloon.obj",
		"hot_air_balloons_balloon_model.png"))

minetest.register_craftitem(hot_air_balloons.get_item(
		"hot_air_balloons:item",
		minetest.translate("hot_air_balloons", "Hot Air Balloon"),
		"hot_air_balloons_balloon.png",
		"hot_air_balloons:balloon"))
		

dofile(modpath .. "/craft.lua")