rgblightstone = {}

function rgblightstone.autofill(pos,player)
	local name = player:get_player_name()
	if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, { protection_bypass = true }) then
		minetest.record_protection_violation(pos, name)
		return
	end
	local meta = minetest.get_meta(pos)
	if (not meta:get_string("channel")) or meta:get_string("channel")=="" then
		local pos_above = {x=pos.x,y=pos.y+1,z=pos.z}
		local node_above = minetest.get_node(pos_above)
		local meta_above = minetest.get_meta(pos_above)
		if string.match(node_above.name,"rgblightstone") and
		meta_above:get_string("channel") and
		tonumber(meta_above:get_string("addrx")) and
		tonumber(meta_above:get_string("addry")) then
			local channel = meta_above:get_string("channel")
			local addrx = meta_above:get_string("addrx")
			local addry = tostring(1+tonumber(meta_above:get_string("addry")))
			meta:set_string("channel",channel)
			meta:set_string("addrx",addrx)
			meta:set_string("addry",addry)
			local message = minetest.colorize("#55FF55","Success: ")..
			                "Auto-filled with channel "..
			                minetest.colorize("#00FFFF",channel)..
			                ", X address "..
			                minetest.colorize("#00FFFF",addrx)..
			                ", and Y address "..
			                minetest.colorize("#00FFFF",addry)..
			                "."
			minetest.chat_send_player(player:get_player_name(),message)
			meta:set_string("infotext","")
		else
			local message = minetest.colorize("#FF0000","ERROR: ").."Node above is not RGB Lightstone or is not configured correctly!"
			minetest.chat_send_player(player:get_player_name(),message)
		end
	end
end

function rgblightstone.handle_digilines(pos,node,channel,msg,truecolor)
	local meta = minetest.get_meta(pos)
	local setchan = meta:get_string("channel")
	if channel ~= setchan then
		return
	end

	local addrx = tonumber(meta:get_string("addrx"))
	local addry = tonumber(meta:get_string("addry"))

	if type(msg) == "table" then
		if not (addrx and addry and type(msg[addry]) == "table" and msg[addry][addrx]) then
			return
		end
		msg = msg[addry][addrx]
	end

	--Validation starts here
	if type(msg) ~= "string" then
		return
	end
	msg = string.upper(msg)
	--Drop a leading # if present (e.g. "#FF55AA")
	if string.sub(msg,1,1) == "#" then
		msg = string.sub(msg,2)
	end
	--Check length
	if string.len(msg) ~= 6 then
		return
	end
	--Make sure there aren't any invalid chars
	if not tonumber(msg,16) then return end
	--Should be a valid hex color by this point

	meta:set_string("color",msg)

	--Split into three colors
	local r = tonumber(string.sub(msg,1,2),16)
	local g = tonumber(string.sub(msg,3,4),16)
	local b = tonumber(string.sub(msg,5,6),16)

	--Convert RGB to HSV... or at least V, for the light
	local v = math.max(r,g,b)
	v = math.floor(v/255*14)
	v = math.max(0,math.min(14,v))

	if truecolor then
		node.name = "rgblightstone:rgblightstone_truecolor_"..v
		minetest.swap_node(pos,node)
		rgblightstone.update_entity(pos)
	else
		--Round to nearest available values and convert to a pixel count in the palette
		r = math.floor(r/32)
		g = math.floor(g/32)
		b = math.floor(b/64) --Blue has one fewer bit

		local paletteidx = 32*g+4*r+b

		--Set the color
		node.name = "rgblightstone:rgblightstone_"..v
		node.param2 = paletteidx
		minetest.swap_node(pos,node)
	end
end

function rgblightstone.handle_fields(pos,_,fields,sender)
			local name = sender:get_player_name()
			if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, { protection_bypass = true }) then
				minetest.record_protection_violation(pos, name)
				return
			end
			local meta = minetest.get_meta(pos)
			if fields.autofill then
				rgblightstone.autofill(pos,sender)
			else
				if fields.channel then
					meta:set_string("channel", fields.channel)
					meta:set_string("infotext","")
				end
				if fields.addrx then meta:set_string("addrx",fields.addrx) end
				if fields.addry then meta:set_string("addry",fields.addry) end
			end
end

function rgblightstone.update_entity(pos)
	local objs = minetest.get_objects_inside_radius(pos,0.5)
	for _,obj in ipairs(objs) do
		if obj:get_luaentity() and obj:get_luaentity().name == "rgblightstone:entity" then
			obj:remove()
		end
	end
	local obj = minetest.add_entity(pos,"rgblightstone:entity")
	local tex = "rgblightstone_white.png^[colorize:#"..minetest.get_meta(pos):get_string("color")..":255"
	obj:set_properties({textures = {tex,tex,tex,tex,tex,tex}})
end

minetest.register_entity("rgblightstone:entity",{
	initial_properties = {
		physical = false,
		collisionbox = {0,0,0,0,0,0},
		visual_size = {x=1,y=1},
		visual = "cube",
		static_save = false,
	},
})

for i=0,14,1 do
	minetest.register_node("rgblightstone:rgblightstone_"..i, {
		tiles = {"rgblightstone_white.png"},
		palette = "rgblightstone_palette.png",
		groups = i == 0 and {cracky = 2,} or {cracky = 2,not_in_creative_inventory = 1,},
		description = i == 0 and "256-Color RGB Lightstone" or "256-Color RGB Lightstone (lit state - you hacker you!)",
		paramtype2 = "color",
		light_source = i,
		drop = "rgblightstone:rgblightstone_0",
		_digistuff_channelcopier_fieldname = "channel",
		_digistuff_channelcopier_onset = function(pos)
			minetest.get_meta(pos):set_string("infotext","")
		end,
		on_construct = function(pos)
			local meta = minetest.get_meta(pos)
			local fs = "size[8,5]"..
			           "field[1,1;6,2;channel;Channel;${channel}]"..
			           "field[1,2;2,2;addrx;X Address;${addrx}]"..
			           "field[5,2;2,2;addry;Y Address;${addry}]"..
			           "button_exit[2.25,3;3,1;submit;Save]"..
			           "button_exit[2.25,4;3,1;autofill;Auto-Fill From Node Above]"..
			           "label[3,2;Leave address blank\nfor individual mode]"
			meta:set_string("formspec",fs)
			meta:set_string("infotext","Not configured! Right-click to set up manually, or punch to auto-fill from the node above.")
			meta:set_string("color","000000")
		end,
		on_punch = function(pos,_,player)
			rgblightstone.autofill(pos,player)
		end,
		on_receive_fields = rgblightstone.handle_fields,
		digiline = {
			wire = {
				rules = {
					{x = 1,y = 0,z = 0},
					{x = -1,y = 0,z = 0},
					{x = 0,y = 0,z = 1},
					{x = 0,y = 0,z = -1},
					{x = 0,y = 1,z = 0},
					{x = 0,y = -1,z = 0},
				},
			},
			receptor = {},
			effector = {
				action = function(pos,node,channel,msg)
					rgblightstone.handle_digilines(pos,node,channel,msg,false)
				end
			}
		}
	})

	minetest.register_node("rgblightstone:rgblightstone_truecolor_"..i, {
		tiles = {"rgblightstone_white.png^[colorize:#000000:255"},
		groups = i == 0 and {cracky = 2,} or {cracky = 2,not_in_creative_inventory = 1,},
		description = i == 0 and "True-Color RGB Lightstone" or "True-Color RGB Lightstone (lit state - you hacker you!)",
		light_source = i,
		drop = "rgblightstone:rgblightstone_truecolor_0",
		_digistuff_channelcopier_fieldname = "channel",
		_digistuff_channelcopier_onset = function(pos)
			minetest.get_meta(pos):set_string("infotext","")
		end,
		on_construct = function(pos)
			local meta = minetest.get_meta(pos)
			local fs = "size[8,5]"..
			           "field[1,1;6,2;channel;Channel;${channel}]"..
			           "field[1,2;2,2;addrx;X Address;${addrx}]"..
			           "field[5,2;2,2;addry;Y Address;${addry}]"..
			           "button_exit[2.25,3;3,1;submit;Save]"..
			           "button_exit[2.25,4;3,1;autofill;Auto-Fill From Node Above]"..
			           "label[3,2;Leave address blank\nfor individual mode]"
			meta:set_string("formspec",fs)
			meta:set_string("infotext","Not configured! Right-click to set up manually, or punch to auto-fill from the node above.")
			meta:set_string("color","000000")
			rgblightstone.update_entity(pos)
		end,
		on_punch = function(pos,_,player)
			rgblightstone.autofill(pos,player)
		end,
		after_destruct = function(pos)
			local objs = minetest.get_objects_inside_radius(pos,0.5)
			for _,obj in ipairs(objs) do
				if obj:get_luaentity() and obj:get_luaentity().name == "rgblightstone:entity" then
					obj:remove()
				end
			end
		end,
		paramtype = "light",
		drawtype = "nodebox",
		node_box = {
			type = "fixed",
			fixed = {{-0.45,-0.45,-0.45,0.45,0.45,0.45}}
		},
		collision_box = {
			type = "fixed",
			fixed = {{-0.5,-0.5,-0.5,0.5,0.5,0.5}}
		},
		selection_box = {
			type = "fixed",
			fixed = {{-0.5,-0.5,-0.5,0.5,0.5,0.5}}
		},
		on_receive_fields = rgblightstone.handle_fields,
		digiline = {
			wire = {
				rules = {
					{x = 1,y = 0,z = 0},
					{x = -1,y = 0,z = 0},
					{x = 0,y = 0,z = 1},
					{x = 0,y = 0,z = -1},
					{x = 0,y = 1,z = 0},
					{x = 0,y = -1,z = 0},
				},
			},
			receptor = {},
			effector = {
				action = function(pos,node,channel,msg)
					rgblightstone.handle_digilines(pos,node,channel,msg,true)
				end
			}
		}
	})
end

local tclist = {}
for i=0,14,1 do table.insert(tclist,"rgblightstone:rgblightstone_truecolor_"..i) end

minetest.register_lbm({
	name = "rgblightstone:restore_entities",
	label = "Restore true-color rgblightstone entities",
	nodenames = tclist,
	run_at_every_load = true,
	action = rgblightstone.update_entity,
})

minetest.register_alias("rgblightstone:rgblightstone","rgblightstone:rgblightstone_0")
minetest.register_alias("rgblightstone:rgblightstone_truecolor","rgblightstone:rgblightstone_truecolor_0")


minetest.register_craft({
	output = "rgblightstone:rgblightstone_0",
	recipe = {
		{"","mesecons_lightstone:lightstone_green_off",""},
		{"mesecons_lightstone:lightstone_red_off","mesecons_luacontroller:luacontroller0000","mesecons_lightstone:lightstone_blue_off"},
		{"","digilines:wire_std_00000000",""}
	}
})

minetest.register_craft({
	output = "rgblightstone:rgblightstone_truecolor_0",
	recipe = {
		{"","rgblightstone:rgblightstone_0",""},
		{"rgblightstone:rgblightstone_0","mesecons_luacontroller:luacontroller0000","rgblightstone:rgblightstone_0"},
		{"","digilines:wire_std_00000000",""}
	}
})
