local S = minetest.get_translator("lzr_laser")

-- List of laser color hex codes.
-- These are the builtin default colors that cannot be changed.
lzr_laser.DEFAULT_LASER_COLORS = {
	[lzr_globals.COLOR_RED] = "FF0000",
	[lzr_globals.COLOR_GREEN] = "00FF00",
	[lzr_globals.COLOR_BLUE] = "1212FF",
	[lzr_globals.COLOR_YELLOW] = "FFFF00",
	[lzr_globals.COLOR_CYAN] = "00FFFF",
	[lzr_globals.COLOR_MAGENTA] = "FF00FF",
	[lzr_globals.COLOR_WHITE] = "FFFFFF",
}
-- These are the user-changable laser colors that will actually
-- be used by the lasers in the game.
-- This table may contain user overrides; otherwise it is
-- equal to the default colors.
lzr_laser.LASER_COLORS = table.copy(lzr_laser.DEFAULT_LASER_COLORS)

local function read_laser_color_settings()
	for c=1, #lzr_globals.COLOR_NAMES do
		local setting = minetest.settings:get("lzr_laser_color_"..lzr_globals.COLOR_NAMES[c])
		if setting then
			local hexcode = string.match(setting, "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]")
			if hexcode then
				lzr_laser.LASER_COLORS[c] = hexcode
				minetest.log("action", "[lzr_laser] Custom laser color read from setting 'lzr_laser_color_"..lzr_globals.COLOR_NAMES[c]..": "..hexcode)
			elseif setting ~= "" then
				minetest.log("warning", "[lzr_laser] Setting 'lzr_laser_color_"..lzr_globals.COLOR_NAMES[c].."' has wrong syntax. Must be a 6-digit hexadecimal number (0-9, A-F).")
			end
		end
	end
end
read_laser_color_settings()

-- List of patterns to apply on lasers to distinguish them by some other
-- way than just color. Implemented to deal with colorblindness.
local LASER_PATTERNS = {
	[lzr_globals.COLOR_RED] = nil, -- no pattern, use a solid line
	[lzr_globals.COLOR_GREEN] = { name = "lzr_laser_pattern_lines.png", size = 16 },
	[lzr_globals.COLOR_BLUE] = { name = "lzr_laser_pattern_dots.png", size = 16 },
	[lzr_globals.COLOR_YELLOW] = { name = "lzr_laser_pattern_checkers.png", size = 16 },
	[lzr_globals.COLOR_CYAN] = { name = "lzr_laser_pattern_long_checkers.png", size = 16 },
	[lzr_globals.COLOR_MAGENTA] = { name = "lzr_laser_pattern_alternating.png", size = 16 },
	[lzr_globals.COLOR_WHITE] = { name = "lzr_laser_pattern_holes.png", size = 32 },
}



-- Shorthand to generate a laser tile. We don't use texture files,
-- we generate them on the fly!
local maketile = function(colorcode, alpha)
	local use_patterns = minetest.settings:get_bool("lzr_patterned_lasers", false)
	local alpha_append = ""
	local pattern_append = ""
	if alpha then
		alpha_append = lzr_globals.LASER_ALPHA_STRING
	end
	local texsize = 16
	if use_patterns then
		local pattern = LASER_PATTERNS[colorcode]
		if pattern ~= nil then
			pattern_append = "^[mask:"..pattern.name
			texsize = pattern.size
		end
	end
	local texture = 
		-- Generate the texture base color
		"([fill:"..texsize.."x"..texsize..":"..
			"#"..lzr_laser.LASER_COLORS[colorcode]..alpha_append..")"
		-- Apply a pattern on the laser, if enabled (allows to distinguish
		-- lasers other than by color to circumvent colorblindness)
		.. pattern_append

	return { name = texture, backface_culling = true }
end

-- List of all possible laser tiles
if lzr_globals.OPAQUE_LASERS then
	lzr_laser.TILE_LASER_R = maketile(lzr_globals.COLOR_RED)
	lzr_laser.TILE_LASER_G = maketile(lzr_globals.COLOR_GREEN)
	lzr_laser.TILE_LASER_B = maketile(lzr_globals.COLOR_BLUE)
	lzr_laser.TILE_LASER_Y = maketile(lzr_globals.COLOR_YELLOW)
	lzr_laser.TILE_LASER_C = maketile(lzr_globals.COLOR_CYAN)
	lzr_laser.TILE_LASER_M = maketile(lzr_globals.COLOR_MAGENTA)
	lzr_laser.TILE_LASER_W = maketile(lzr_globals.COLOR_WHITE)
	lzr_laser.ALPHA_LASER = "clip"
else
	lzr_laser.TILE_LASER_R = maketile(lzr_globals.COLOR_RED, true)
	lzr_laser.TILE_LASER_G = maketile(lzr_globals.COLOR_GREEN, true)
	lzr_laser.TILE_LASER_B = maketile(lzr_globals.COLOR_BLUE, true)
	lzr_laser.TILE_LASER_Y = maketile(lzr_globals.COLOR_YELLOW, true)
	lzr_laser.TILE_LASER_C = maketile(lzr_globals.COLOR_CYAN, true)
	lzr_laser.TILE_LASER_M = maketile(lzr_globals.COLOR_MAGENTA, true)
	lzr_laser.TILE_LASER_W = maketile(lzr_globals.COLOR_WHITE, true)
	lzr_laser.ALPHA_LASER = "blend"
end

-- Distance from center to side of the laser beam square. Not really the radius, but it sounds cooler. :P
local LASER_RADIUS = -1/16

-- Register laser nodes, i.e. the actual
-- laser beams in the map.

--[[ This registers a node for every possible laser combination.
A laser node contains 1 to 3 laser beams, each along the
X, Y and Z axis. Also, each laser beam can have one of
each possible laser color (defined by colorcodes from 0
to lzr_globals.MAX_COLORCODE).
When there is no laser on any axis, there is no need
for a laser node.

The number of registered nodes is
    (<number of laser colors + 1> ^ 3) - 1
]]

for color_x=0, lzr_globals.MAX_COLORCODE do
for color_y=0, lzr_globals.MAX_COLORCODE do
for color_z=0, lzr_globals.MAX_COLORCODE do

	local dirstring = color_x .. color_y .. color_z
	local dirs = lzr_laser.dirstring_to_dirs(dirstring)

	-- Count the active axes
	local axes = 0
	local axes_active = {x=false,y=false,z=false}
	for a=1,3 do
		if dirs[a] ~= 0 then
			axes = axes + 1
			if a == 1 then
				axes_active.x = true
			elseif a == 2 then
				axes_active.y = true
			elseif a == 3 then
				axes_active.z = true
			end
		end
	end
	local color2tile = function(colorcode)
		if colorcode == 0 then
			return "blank.png"
		end
		if colorcode == lzr_globals.COLOR_RED then
			return lzr_laser.TILE_LASER_R
		elseif colorcode == lzr_globals.COLOR_GREEN then
			return lzr_laser.TILE_LASER_G
		elseif colorcode == lzr_globals.COLOR_YELLOW then
			return lzr_laser.TILE_LASER_Y
		elseif colorcode == lzr_globals.COLOR_BLUE then
			return lzr_laser.TILE_LASER_B
		elseif colorcode == lzr_globals.COLOR_CYAN then
			return lzr_laser.TILE_LASER_C
		elseif colorcode == lzr_globals.COLOR_MAGENTA then
			return lzr_laser.TILE_LASER_M
		elseif colorcode == lzr_globals.COLOR_WHITE then
			return lzr_laser.TILE_LASER_W
		else
			-- error
			return "no_texture.png"
		end
	end

	-- Pick a mesh depending on the axes on where to put
	-- a laser beam.
	-- The meshes are made so that the "ends" of the lasers
	-- are "open", i.e. don't have an additional face.
	-- This ensures the laser beam looks like a real
	-- continuous beam reather than a sequence of nodes.

	local tex, mesh
	-- Single laser
	if axes == 1 then
		-- Simple: Just pick a mesh for the laser direction, and then the color
		if axes_active.x then
			mesh = "lzr_laser_laser_100.obj"
			tex = { color2tile(color_x) }
		elseif axes_active.y then
			mesh = "lzr_laser_laser_010.obj"
			tex = { color2tile(color_y)}
		else
			mesh = "lzr_laser_laser_001.obj"
			tex = { color2tile(color_z) }
		end
	-- 2 lasers crossing
	elseif axes == 2 then
		-- A bit trickier: We have two primary colors from 2 lasers,
		-- but at the crossing, we mix both colors with the 'combined' var.
		if axes_active.x == false then
			mesh = "lzr_laser_laser_011.obj"
			-- Color mixing is just a bitwise OR of 2 colorcodes. Because the colorcodes
			-- are aligned in the correct way for this to work.
			local combined = bit.bor(color_y, color_z)
			tex = { color2tile(combined), color2tile(color_y), color2tile(color_z) }
		elseif axes_active.y == false then
			mesh = "lzr_laser_laser_101.obj"
			local combined = bit.bor(color_x, color_z)
			tex = { color2tile(color_x), color2tile(combined), color2tile(color_z) }
		else
			mesh = "lzr_laser_laser_110.obj"
			local combined = bit.bor(color_x, color_y)
			tex = { color2tile(color_x), color2tile(color_y), color2tile(combined) }
		end
		-- Note
	-- 3 lasers crossing
	elseif axes == 3 then
		-- Easy again: Pick a mesh and 3 colors for the 3 axes
		mesh = "lzr_laser_laser_111.obj"
		tex = { color2tile(color_x), color2tile(color_y), color2tile(color_z) }
	end

	-- This generates an unique number for each possible laser combination
	local lasergroup = lzr_laser.colors_to_laser_group(color_x, color_y, color_z)
	if tex then
		-- Finally register the laser
		minetest.register_node("lzr_laser:laser_"..dirstring, {
			--~ Laser block description. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
			description = S("Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
			paramtype = "light",
			light_source = lzr_globals.LASER_GLOW,
			drawtype = "mesh",
			mesh = mesh,
			sunlight_propagates = true,
			walkable = false,
			use_texture_alpha = lzr_laser.ALPHA_LASER,
			tiles = tex,
			pointable = false,
			buildable_to = true,

			groups = { laser = lasergroup, not_in_creative_inventory = 1, dig_immediate = 3 },
			drop = "",
		})

		if axes == 1 then
			-- Combination node: Barrier + laser
			minetest.register_node("lzr_laser:barrier_laser_"..dirstring, {
				--~ Description of a block that is both laser and invisible barrier. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
				description = S("Barrier Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
				paramtype = "light",
				light_source = lzr_globals.LASER_GLOW,
				drawtype = "mesh",
				mesh = mesh,
				sunlight_propagates = true,
				walkable = true,
				use_texture_alpha = lzr_laser.ALPHA_LASER,
				tiles = tex,
				buildable_to = false,

				-- Can't point through or select; player should not be able to
				-- build at the level borders or point anything through it.
				pointable = "blocking",
				pointabilities = {
					nodes = {
						["group:barrier"] = true,
					}
				},
				collision_box = { type = "regular" },

				groups = { breakable = 1, barrier = 2, laser = lasergroup, not_in_creative_inventory = 1 },
				drop = "",
			})

			-- Combination node: Rain Membrane + laser
			minetest.register_node("lzr_laser:rain_membrane_laser_"..dirstring, {
				--~ Description of a block that is both laser and invisible barrier that lets rain through but not the player. @1 = color code uniquely identifying the color(s) of the laser beam(s) in that node
				description = S("Rain Membrane Laser (@1)", lzr_laser.dirstring_to_colstring(dirstring)),
				paramtype = "light",
				light_source = lzr_globals.LASER_GLOW,
				drawtype = "mesh",
				mesh = mesh,
				sunlight_propagates = true,
				walkable = true,
				use_texture_alpha = lzr_laser.ALPHA_LASER,
				tiles = tex,
				buildable_to = false,

				-- Can't point through or select; player should not be able to
				-- build at the level borders or point anything through it.
				pointable = "blocking",
				pointabilities = {
					nodes = {
						["group:barrier"] = true,
					}
				},

				collision_box = lzr_globals.RAIN_MEMBRANE_COLLISION_BOX,
				selection_box = {
					type = "regular",
				},
				is_ground_content = false,

				groups = { breakable = 1, rain_membrane = 1, barrier = 2, laser = lasergroup, not_in_creative_inventory = 1 },
				drop = "",
			})

		end

	end
end
end
end
