
-- TODO: play sound while working
-- TODO: play sound when emptying a bucket
-- TODO: store correct bucket texture when loading the world anew
-- TODO: show particles when running? distinguish between running/idle state? (with punch?)

-- well for getting water
--   * has some storage space for buckets (filled with water, river water or empty)
--   * only the owner can use the bucket store and the well
--   * the bucket will be added as an entity and slowly rotate;
--     once filled, the texture of the bucket is changed
--   * full (water or river water) buckets can be emptied
--   * by default public; but can also be made private


-- how many seconds does it take to fill a bucket?
cottages.water_fill_time = 10

local S = cottages.S

-- code taken from the itemframes mod in homedecor
-- (the relevant functions are sadly private there and thus cannot be reused)
local tmp = {}
minetest.register_entity("cottages:bucket_entity",{
	hp_max = 1,
	visual="wielditem",
	visual_size={x = 0.33, y = 0.33},
	collisionbox = {0, 0, 0, 0, 0, 0},
	physical = false,
	textures = {"air"},
	on_activate = function(self, staticdata)
		if tmp.nodename ~= nil and tmp.texture ~= nil then
			self.nodename = tmp.nodename
			tmp.nodename = nil
			self.texture = tmp.texture
			tmp.texture = nil
		else
			if staticdata ~= nil and staticdata ~= "" then
				local data = staticdata:split(';')
				if data and data[1] and data[2] then
					self.nodename = data[1]
					self.texture = data[2]
				end
			end
		end
		if self.texture ~= nil then
			self.object:set_properties({textures = {self.texture}})
		end
		self.object:set_properties({automatic_rotate = 1})
		if self.texture ~= nil and self.nodename ~= nil then
			local entity_pos = vector.round(self.object:get_pos())
			local objs = minetest.get_objects_inside_radius(entity_pos, 0.5)
			for _, obj in ipairs(objs) do
				if obj ~= self.object and
				   obj:get_luaentity() and
				   obj:get_luaentity().name == "cottages:bucket_entity" and
				   obj:get_luaentity().nodename == self.nodename and
				   obj:get_properties() and
				   obj:get_properties().textures and
				   obj:get_properties().textures[1] == self.texture then
					minetest.log("action","[cottages] Removing extra " ..
						self.texture .. " found in " .. self.nodename .. " at " ..
						minetest.pos_to_string(entity_pos))
					self.object:remove()
					break
				end
			end
		end
	end,
	get_staticdata = function(self)
		if self.nodename ~= nil and self.texture ~= nil then
			return self.nodename .. ';' .. self.texture
		end
		return ""
	end,
})

cottages.water_gen_fill_bucket = function(pos)
	if( not(pos)) then
		return
	end
	local meta = minetest.get_meta(pos)
	local bucket = meta:get_string("bucket")
	-- nothing to do
	if( not(bucket) or bucket ~= "bucket:bucket_empty") then
		return
	end
	-- abort if the water has not been running long enough
	-- (the player may have removed a bucket before it was full)
	start = meta:get_string("fillstarttime")
	if( (minetest.get_us_time()/1000000) - tonumber(start) < cottages.water_fill_time -2) then
		return
	end

	-- the bucket has been filled
	meta:set_string("bucket", "bucket:bucket_river_water")

	-- change the texture of the bucket to that of one filled with river water
	local objs = nil
	objs = minetest.get_objects_inside_radius(pos, .5)
	if objs then
		for _, obj in ipairs(objs) do
			if obj and obj:get_luaentity() and obj:get_luaentity().name == "cottages:bucket_entity" then
				obj:set_properties( { textures = { "bucket:bucket_river_water" }})
				obj:get_luaentity().nodename = "bucket:bucket_river_water"
				obj:get_luaentity().texture = "bucket:bucket_river_water"
			end
		end
	end
end


minetest.register_node("cottages:water_gen", {
	description = "Tree Trunk Well",
	tiles = {"default_tree_top.png", "default_tree.png^[transformR90", "default_tree.png^[transformR90"},
	drawtype = "nodebox",
	paramtype  = "light",
	paramtype2 = "facedir",
	is_ground_content = false,
	groups = {tree = 1, choppy = 2, cracky = 1, flammable = 2},
	sounds = cottages.sounds.wood,
	node_box = {
		type = "fixed",
		fixed = {
			-- floor of water bassin
			{-0.5, -0.5+(3/16), -0.5,  0.5,   -0.5+(4/16),  0.5},
			-- walls
			{-0.5, -0.5+(3/16), -0.5,  0.5,        (4/16), -0.5+(2/16)},
			{-0.5, -0.5+(3/16), -0.5, -0.5+(2/16), (4/16),  0.5},
			{ 0.5, -0.5+(3/16),  0.5,  0.5-(2/16), (4/16), -0.5},
			{ 0.5, -0.5+(3/16),  0.5, -0.5+(2/16), (4/16),  0.5-(2/16)},
			-- feet
			{-0.5+(3/16), -0.5, -0.5+(3/16), -0.5+(6/16), -0.5+(3/16),  0.5-(3/16)},
			{ 0.5-(3/16), -0.5, -0.5+(3/16),  0.5-(6/16), -0.5+(3/16),  0.5-(3/16)},
			-- real pump
			{ 0.5-(4/16), -0.5,        -(2/16),  0.5, 0.5+(4/16),  (2/16)},
			-- water pipe inside wooden stem
			{ 0.5-(8/16), 0.5+(1/16),  -(1/16),  0.5, 0.5+(3/16),  (1/16)},
			-- where the water comes out
			{ 0.5-(15/32), 0.5,        -(1/32),  0.5-(12/32), 0.5+(1/16),  (1/32)},
		},
	},
	selection_box = {
		type = "fixed",
		fixed = { -0.5, -0.5, -0.5, 0.5, 0.5+(4/16), 0.5 }
	},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		local spos = pos.x .. "," .. pos.y .. "," .. pos.z
		meta:set_string("formspec",
			"size[8,9]" ..
			"label[3.0,0.0;Tree trunk well]"..
			"label[1.5,0.7;Punch the well while wielding an empty bucket.]"..
			"label[1.5,1.0;Your bucket will slowly be filled with river water.]"..
			"label[1.5,1.3;Punch again to get the bucket back when it is full.]"..
			"label[1.0,2.9;Internal bucket storage (passive storage only):]"..
			"item_image[0.2,0.7;1.0,1.0;bucket:bucket_empty]"..
			"item_image[0.2,1.7;1.0,1.0;bucket:bucket_river_water]"..
			"label[1.5,1.9;Punch well with full water bucket in order to empty bucket.]"..
			"button_exit[6.0,0.0;2,0.5;public;"..S("Public?").."]"..
			"list[nodemeta:" .. spos .. ";main;1,3.3;8,1;]" ..
			"list[current_player;main;0,4.85;8,1;]" ..
			"list[current_player;main;0,6.08;8,3;8]" ..
			"listring[nodemeta:" .. spos .. ";main]" ..
			"listring[current_player;main]")
		local inv = meta:get_inventory()
		inv:set_size('main', 6)
		meta:set_string("infotext", S("Public tree trunk well")) -- (punch with empty bucket to fill bucket)")
	end,
	after_place_node = function(pos, placer)
		local meta = minetest.get_meta(pos)
		meta:set_string("owner", placer:get_player_name() or "")
		meta:set_string("infotext", S("Public tree trunk well (owned by %s)"):format(meta:get_string("owner")))
		-- no bucket loaded
		meta:set_string("bucket", "")
		meta:set_string("public", "public")
		end,
	can_dig = function(pos,player)
		local meta = minetest.get_meta(pos);
		local inv = meta:get_inventory()
		local bucket = meta:get_string("bucket")
		local start = meta:get_string("fillstarttime")
		return inv:is_empty("main")
			and default.can_interact_with_node(player, pos)
			and (not(bucket) or bucket == "")
			and ((not(start) or start == "" or
				(minetest.get_us_time()/1000000) - tonumber(start)
					>= cottages.water_fill_time -2))
	end,
	-- no inventory move allowed
	allow_metadata_inventory_move = function(pos, from_list, from_index,
			to_list, to_index, count, player)
		return 0
	end,
	allow_metadata_inventory_put = function(pos, listname, index, stack, player)
		local meta = minetest.get_meta(pos)
		if not(stack) or not cottages.player_can_use(meta, player) then
			return 0
		end
		local inv = meta:get_inventory()
		-- only for buckets
		local sname = stack:get_name()
		if(   sname ~= "bucket:bucket_empty"
		  and sname ~= "bucket:bucket_water"
		  and sname ~= "bucket:bucket_river_water") then
			return 0
		end
		return stack:get_count()
	end,
	allow_metadata_inventory_take = function(pos, listname, index, stack, player)
		local meta = minetest.get_meta(pos)
		if not(cottages.player_can_use(meta, player)) then
			return 0
		end
		return stack:get_count()
	end,
	on_blast = function() end,
	on_receive_fields = function(pos, formname, fields, sender)
		cottages.switch_public(pos, formname, fields, sender, 'tree trunk well')
	end,
	-- punch to place and retrieve bucket
	on_punch = function(pos, node, puncher, pointed_thing)
		if( not( pos ) or not( node ) or not( puncher )) then
			return
		end
		-- only the owner can use the well
		local name = puncher:get_player_name()
               	local meta = minetest.get_meta(pos)
		local owner = meta:get_string("owner")
		local public = meta:get_string("public")
		if( name ~= owner and public~="public") then
			minetest.chat_send_player( name,
				S("This tree trunk well is owned by %s. You can't use it."):format(owner))
			return
		end

		-- we will either add or take from the players inventory
		local pinv = puncher:get_inventory()

		-- is the well working on something? (either empty or full bucket)
		local bucket = meta:get_string("bucket")
		-- there is a bucket loaded - either empty or full
		if( bucket and bucket~="" and bucket ~= "bucket:bucket_empty") then
			if( not(pinv:room_for_item("main", bucket))) then
				minetest.chat_send_player( puncher:get_player_name(),
					S("Sorry. You have no room for the bucket. Please free some "..
					"space in your inventory first!"))
				return
			end
		elseif( bucket and bucket == "bucket:bucket_empty") then
			minetest.chat_send_player( puncher:get_player_name(),
				S("Please wait until your bucket has been filled."))
			-- do not give the empty bucket back immediately
			return
		end

		-- remove the old entity (either a bucket will be placed now or a bucket taken)
		local objs = nil
		objs = minetest.get_objects_inside_radius(pos, .5)
		if objs then
			for _, obj in ipairs(objs) do
				if obj and obj:get_luaentity() and obj:get_luaentity().name == "cottages:bucket_entity" then
					obj:remove()
				end
			end
		end

		-- the player gets the bucket (either empty or full) into his inventory
		if( bucket and bucket ~= "") then
			pinv:add_item("main", bucket )
			meta:set_string("bucket", "")
			-- we are done
			return
		end

		-- punching with empty bucket will put that bucket into the well (as an entity)
		-- and will slowly fill it
		local wielded = puncher:get_wielded_item()
		if(    wielded
		    and wielded:get_name()
		    and wielded:get_name() == "bucket:bucket_empty") then
			-- remember that we got a bucket loaded
			meta:set_string("bucket", "bucket:bucket_empty")
			-- create the entity
			tmp.nodename = "bucket:bucket_empty"
			-- TODO: add a special texture with a handle for the bucket here
			tmp.texture = "bucket:bucket_empty"
			local e = minetest.add_entity({x=pos.x,y=pos.y+(4/16),z=pos.z},"cottages:bucket_entity")
			-- fill the bucket with water
			minetest.after(cottages.water_fill_time, cottages.water_gen_fill_bucket, pos)
			-- the bucket will only be filled if the water ran long enough
			meta:set_string("fillstarttime", tostring(minetest.get_us_time()/1000000)) 
			-- remove the bucket from the players inventory
			pinv:remove_item( "main", "bucket:bucket_empty")
 			return;
		end
		-- buckets can also be emptied here
		if(    wielded
		    and wielded:get_name()
		    and (wielded:get_name() == "bucket:bucket_water"
		      or wielded:get_name() == "bucket:bucket_river_water")
		    and (pinv:room_for_item("main", "bucket:bucket_empty"))) then
			-- remove the full bucket from the players inventory
			pinv:remove_item( "main", wielded:get_name())
			-- add empty bucket
			pinv:add_item("main", "bucket:bucket_empty")
			-- TODO: play diffrent sound when pouring a bucket
 			return;
		end
		    
		-- else check if there is a bucket that can be retrieved
		meta:set_string("bucket","")
	end,
})


-- a well (will fill water buckets) crafted from wooden materials
minetest.register_craft({
	output = 'cottages:water_gen',
	recipe = {
		{'default:stick', '', ''},
		{'default:tree', 'bucket:bucket_empty',  'bucket:bucket_empty'},
		{'default:tree', 'default:tree', 'default:tree'},
	}
})

