------------------------------------------------------
--        ___ _                                     --
--       | __| |___ _ __  _____ __ _____ _ _        --
--       | _|| / -_) '_ \/ _ \ V  V / -_) '_|       --
--       |___|_\___| .__/\___/\_/\_/\___|_|         --
--         _    _  |_| _   _   _                    --
--        | |  (_)__ _| |_| |_(_)_ _  __ _          --
--        | |__| / _` | ' \  _| | ' \/ _` |         --
--        |____|_\__, |_||_\__|_|_||_\__, |         --
--               |___/               |___/          --
------------------------------------------------------
--                   Functions                      --
------------------------------------------------------
-------------------------------------------
--          Floodlight Formspec          --
-------------------------------------------
local function get_formspec_flood(power,tilt,rotate)
	local rotate  = rotate or 0
	local tilt    = tilt or 0
	local per_rot = (math.abs(rotate)/45)*100
	local percent = (math.abs(tilt)/20)*100

	local final ="size[8,3]"..
	             ele.formspec.power_meter(power)..
				 -- rotate

				 "image[3.5,0.25;2.8,1;elepower_gui_barbg.png^[transformR90]"..
				 "image[4.43,2.4;0.5,0.5;elepower_lighting_flood_arrow_icon.png^[transformR90]"..
				 "tooltip[3.5,1.45;2.25,0.4;"..rotate.." Degrees;#30434c;#f9f9f9]"..
				 --"button[5.15,1.45;0.75,0.75;rot;+]"..
				 --"tooltip[5.15,1.45;0.75,0.75;+1 Degrees;#30434c;#f9f9f9]"..				 
				 --"button[4.35,1.45;0.75,0.75;rot;0]"..
				 --"tooltip[4.35,1.45;0.75,0.75;Reset;#30434c;#f9f9f9]"..
				 --"button[3.5,1.45;0.75,0.75;rot;-]"..
				 --"tooltip[3.5,1.45;0.75,0.75;-1 Degrees;#30434c;#f9f9f9]"..
				 --"image[3.5,0.25;2.8,1;elepower_lighting_flood_tilt_gauge.png^[transformR90]"..

				 "scrollbaroptions[min=-45;max=45;smallstep=1;largestep=5;arrows=show]"..
				 "scrollbar[3.5,1.45;2.25,0.45;horizontal;rot;"..rotate.."]"..

				 "scrollbaroptions[min=-20;max=20;smallstep=1;largestep=5;arrows=show]"..
				 "scrollbar[7.25,0;0.4,2.4;vertical;tilt;"..(tilt).."]"..
				 -- tilt
				 "image[6.25,0;1,2.8;elepower_gui_barbg.png]"..
				 "image[6.5,2.45;0.5,0.5;elepower_lighting_flood_arrow_icon.png]"..
				 "tooltip[7.25,0;1,2.6;"..(tilt).." Degrees;#30434c;#f9f9f9]"
				 --"button[7.25,0.05;0.75,0.75;tilt;+]"..
				 --"tooltip[7.25,0.05;0.75,0.75;+1 Degrees;#30434c;#f9f9f9]"..
				 --"button[7.25,.9;0.75,0.75;tilt;0]"..
				 --"tooltip[7.25,.9;0.75,0.75;Reset;#30434c;#f9f9f9]"..
				 --"button[7.25,1.75;0.75,0.75;tilt;-]"..
				 --"tooltip[7.25,1.75;0.75,0.75;-1 Degrees;#30434c;#f9f9f9]"
	
	if rotate > 0 then
		final = final.."image[4.62,0.25;1.4,1;elepower_gui_barbg.png^[lowpart:"..per_rot..":elepower_gui_bar.png^[transformR270]"
		
	elseif rotate < 0 then
		final = final.."image[3.5,0.25;1.4,1;elepower_gui_barbg.png^[lowpart:"..per_rot..":elepower_gui_bar.png^[transformR90]"
	end
	
	if tilt < 0 then
		final = final.."image[6.25,0;1,1.4;elepower_gui_barbg.png^[lowpart:"..percent..":elepower_gui_bar.png]"
		
	elseif tilt > 0 then
		final = final.."image[6.25,1.22;1,1.4;elepower_gui_barbg.png^[lowpart:"..percent..":elepower_gui_bar.png^[transformR180]"
		
	end
	
	final = final.."image[3.5,0.25;2.8,1;elepower_lighting_flood_rotate_gauge.png^[transformR90]"
	final = final.."image[6.25,0;1,2.8;elepower_lighting_flood_tilt_gauge.png]"
	
	return final
end

-- register flood on_recieve fields
function elepower_lighting.flood_on_recieve_fields(pos, formname, fields, player)
	
	local meta = minetest.get_meta(pos)
	
	if fields.quit then
		return
	end
	
	if fields.rot then
		local split = string.split(fields.rot, ":")
		local new_rot = tonumber(split[2])		
		meta:set_int("rotate",new_rot)
		
		if meta:get_int("on_off") == 1 then
			elepower_lighting.remove_flood_light_fill(pos)
			elepower_lighting.add_flood_light_fill(pos)
		end		
		
	end
	
	if fields.tilt then
		local split = string.split(fields.tilt, ":")
		local new_tilt = tonumber(split[2])
		meta:set_int("tilt", new_tilt)
		
		if meta:get_int("on_off") == 1 then
			elepower_lighting.remove_flood_light_fill(pos)
			elepower_lighting.add_flood_light_fill(pos)
		end		
	end
	--minetest.debug(dump(fields))	
end

-------------------------------------------
-- Converts node param2 into a primary   --
-- axis and the secondary axis, needed   --
-- to workout and place light_fill --
-------------------------------------------
function elepower_lighting.p2_to_axis(node_param2)	
	-- first_key = primary axis, num_key = param2, value = secondary axis/+-
	local p2_conv_table = {x = {[0]="z:+1",[2]="z:-1", [4]="y:-1", [6]="y:+1", [8]="y:+1",[10]="y:-1",[20]="z:+1",[22]="z:-1"}, 
						   y = {[5]="x:+1",[7]="x:-1", [9]="x:+1",[11]="x:-1",[12]="z:+1",[14]="z:-1",[16]="z:+1",[18]="z:-1"}, 
						   z = {[1]="x:+1",[3]="x:-1",[13]="y:-1",[15]="y:+1",[17]="y:+1",[19]="y:-1",[21]="x:-1",[23]="x:+1"}}	
	local light_strip_axis
	
		for xyz,all_p2 in pairs(p2_conv_table) do
			for p2,sec_axis in pairs(all_p2) do
				if node_param2 == p2 then
					local second_axis_v = string.split(sec_axis, ":")
					light_strip_axis = {[xyz] = 1,[second_axis_v[1].."s"] = tonumber(second_axis_v[2])}
					break
				end				
			end			
		end
	return light_strip_axis
end

---------------------------------------------
-- Simply adds or removes light_fill --
---------------------------------------------
function elepower_lighting.add_remove_light_fill(pos,light_strip_axis,light_shape,add_remove)
	local x = light_strip_axis.x or 0
	local y = light_strip_axis.y or 0
	local z = light_strip_axis.z or 0
	
	local xs = light_strip_axis.xs or 0
	local ys = light_strip_axis.ys or 0
	local zs = light_strip_axis.zs or 0
	local mt_add_remove = minetest.remove_node
	local node_name = "elepower_lighting:light_fill"
	local add_node
	
	-- used for adding/setting nodes
	if add_remove == 1 then
		mt_add_remove = minetest.set_node
		node_name = "air"
		add_node = {name = "elepower_lighting:light_fill"}
	end
	
	if light_shape == "3x1" then
		local pos_p = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
		local pos_n = {x=pos.x-x, y=pos.y-y, z=pos.z-z}					
		
		local poses = {pos_p,pos_n}
		
		for k,p in pairs(poses) do
			if minetest.get_node(p).name == node_name then
				mt_add_remove(p,add_node)
			end	
		end
		
	elseif light_shape == "3x2" then
		local pos_p = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
		local pos_n = {x=pos.x-x, y=pos.y-y, z=pos.z-z}					
		local pos_ps = {x=pos.x+x+xs, y=pos.y+y+ys, z=pos.z+z+zs}
		local pos_cs = {x=pos.x+xs, y=pos.y+ys, z=pos.z+zs}
		local pos_ns = {x=pos.x-x+xs, y=pos.y-y+ys, z=pos.z-z+zs}

		local poses = {pos_p,pos_n,pos_ps,pos_cs,pos_ns}

		for k,p in pairs(poses) do
			if minetest.get_node(p).name == node_name then
				mt_add_remove(p,add_node)
			end	
		end					
	end
end
---------------------------------------------
--      Add Flood Light Light nodes        --
---------------------------------------------
function elepower_lighting.add_flood_light_fill(pos)
	local meta   = minetest.get_meta(pos)
	local node_p2  = minetest.get_node(pos).param2
	local rel_x_y
	
	--1st axis = face dir, 2nd axis = relative vertical(tilt)
	local face_dir = {["z:+1"] = {[0]="y:+1",[12]="x:+1",[16]="x:-1",[20]="y:-1"},   -- North
			    	  ["x:+1"] = {[1]="y:+1", [5]="z:+1", [9]="z:-1",[23]="y:-1"},   -- East
					  ["z:-1"] = {[2]="y:+1",[14]="x:+1",[18]="x:-1",[22]="y:-1"},   -- South
					  ["x:-1"] = {[3]="y:+1", [7]="z:-1",[11]="z:-1",[21]="y:-1"},   -- West
					  ["y:+1"] = {[6]="z:+1", [8]="z:-1",[15]="x:+1",[17]="x:-1"},   -- Up
					  ["y:-1"] = {[4]="z:+1",[10]="z:-1",[13]="x:+1",[19]="x:-1"}}   -- Down 
	
	-- Rotation reference table
	local rot_dir = {[0] = {x = "x",x_v = "+1",y = "z",y_v = "+1", z="y"},
					 [1] = {x = "z",x_v = "-1",y = "x",y_v = "+1", z="y"},
					 [2] = {x = "x",x_v = "-1",y = "z",y_v = "-1", z="y"},
					 [3] = {x = "z",x_v = "+1",y = "x",y_v = "-1", z="y"},
					 
					 [4] = {x = "x",x_v = "+1",y = "y",y_v = "-1",z="z"},
					 [5] = {x = "y",x_v = "+1",y = "x",y_v = "+1",z="z"},
					 [6] = {x = "x",x_v = "-1",y = "y",y_v = "+1",z="z"},
					 [7] = {x = "y",x_v = "-1",y = "x",y_v = "-1",z="z"},
					 
					 [8] = {x = "x",x_v = "+1",y = "y",y_v = "+1",z="z"},
					 [9] = {x = "y",x_v = "-1",y = "x",y_v = "+1",z="z"},
					 [10] = {x = "x",x_v = "-1",y = "y",y_v = "-1",z="z"},
					 [11] = {x = "y",x_v = "+1",y = "x",y_v = "-1",z="z"},
					 
					 [12] = {x = "y",x_v = "-1",y = "z",y_v = "+1",z="x"},					 
					 [13] = {x = "z",x_v = "-1",y = "y",y_v = "-1",z="x"},
					 [14] = {x = "y",x_v = "+1",y = "z",y_v = "-1",z="x"},
					 [15] = {x = "z",x_v = "+1",y = "y",y_v = "+1",z="x"},
					 
					 [16] = {x = "y",x_v = "+1",y = "z",y_v = "+1",z="x"},
					 [17] = {x = "z",x_v = "-1",y = "y",y_v = "+1",z="x"},
					 [18] = {x = "y",x_v = "-1",y = "z",y_v = "-1",z="x"},
					 [19] = {x = "z",x_v = "+1",y = "y",y_v = "-1",z="x"},
					 
					 [20] = {x = "x",x_v = "+1",y = "z",y_v = "+1", z="y"},
					 [21] = {x = "z",x_v = "+1",y = "x",y_v = "-1", z="y"},
					 [22] = {x = "x",x_v = "-1",y = "z",y_v = "-1", z="y"},
					 [23] = {x = "z",x_v = "-1",y = "x",y_v = "+1", z="y"},
					}
	
	for axis,p2s in pairs(face_dir) do
		for p2,rel_vert in pairs(p2s) do
			if node_p2 == p2 then
				local sep_rel_x_axis = string.split(axis,":")
				local sep_rel_y_axis = string.split(rel_vert,":")
					  rel_x_y = {[sep_rel_x_axis[1].."x"] = sep_rel_x_axis[2], 
								   [sep_rel_y_axis[1].."y"] = sep_rel_y_axis[2],
								   [sep_rel_y_axis[1].."z"] = sep_rel_y_axis[4],
								    x =     sep_rel_x_axis[1],
								    x_val = sep_rel_x_axis[2],
								    y =     sep_rel_y_axis[1],
								    y_val = sep_rel_y_axis[2]
								}
					   rot_x_y = rot_dir[node_p2]
			end
		end
	end        

	local light_range = 30
	local tilt_angle = meta:get_int("tilt")
	local rot_angle = meta:get_int("rotate")
	local angle = 90 - rot_angle
	
	-- Start of Raycast Calculations --
	-- work out rotation find pt on circle - x = cx + r * cos(a) // y = cy + r * sin(a)
	-- eg x = rel-x-origin + (light_range*cos((90-rot_angle)*radians)
	local x_rel = pos[rot_x_y.x] + (math.floor((30*math.cos(angle*0.0174533))))*tonumber(rot_x_y.x_v)
	local y_rel = pos[rot_x_y.y] + (math.floor((30*math.sin(angle*0.0174533))))*tonumber(rot_x_y.y_v)
		
	local pos_rot = {[rot_x_y.x] = x_rel,[rot_x_y.y] = y_rel, [rot_x_y.z] = pos[rot_x_y.z]}

	-- work out gradient from angle (math.tan needs radians=degrees*0.0174533...)
	local grad = math.tan(tilt_angle*0.0174533)
	local y_end = math.floor(light_range*grad)

	local xx = (rel_x_y.xx or 0)*light_range
	local yx = (rel_x_y.yx or 0)*light_range
	local zx = (rel_x_y.zx or 0)*light_range

	local xy = (rel_x_y.xy or 0)*y_end 
	local yy = (rel_x_y.yy or 0)*y_end 
	local zy = (rel_x_y.zy or 0)*y_end 
	
	-- pos_s (start) simply add relative x  
	local pos_s = {x=pos.x+(xx/light_range),y=pos.y+(yx/light_range),z=pos.z+(zx/light_range)}
	-- pos_e (end) add both relative x and relative y
	local pos_e = {x=pos_rot.x+xx+xy,y=pos_rot.y+yx+yy,z=pos_rot.z+zx+zy}
	
	meta:set_string("flood_light_pos_s", minetest.serialize(pos_s))
	meta:set_string("flood_light_pos_e", minetest.serialize(pos_e))
	
	local ray = minetest.raycast(pos_s,pos_e,false,true)
	local ray_next = ray:next()	
	local end_pos	

	while ray_next do
		local name = minetest.get_node(ray_next.under).name
		local node_draw = minetest.registered_items[name].drawtype
		
		if node_draw ~= "plantlike" and
		   node_draw ~= "firelike" and 
		   node_draw ~= "raillike" and
		   node_draw ~= "torchlike" and
		   node_draw ~= "signlike" and
		   name ~= "elepower_lighting:light_fill" then
			
			local e_pos = ray_next.under
			meta:set_string("flood_light_end", minetest.serialize(e_pos))
			
			end_pos = {x=e_pos.x-(xx/light_range),y=e_pos.y-(yx/light_range),z=e_pos.z-(zx/light_range)}
			break
		end
		ray_next = ray:next()
	end	
	
	local tot = 30
		if end_pos then
			tot = math.abs(end_pos[rel_x_y.x] - pos[rel_x_y.x])
		end
		
	-- Start of light fill calculations 
	local flood_fill_pos = {}
		for i = 1,tot,1 do 
			local new_pos = table.copy(pos)
			
			-- calculate rotation position
			local x_rel = new_pos[rot_x_y.x] + ((math.floor((i*math.cos(angle*0.0174533))))*tonumber(rot_x_y.x_v)) + 1*tonumber(rot_x_y.x_v) -- last + removes offset from carrier "1"
			local y_rel = new_pos[rot_x_y.y] + (math.floor((i*math.sin(angle*0.0174533))))*tonumber(rot_x_y.y_v)
		
			local pos_rot = {[rot_x_y.x] = x_rel,[rot_x_y.y] = y_rel, [rot_x_y.z] = new_pos[rot_x_y.z]}
			
			-- adjust for tilt
			 pos_rot[rel_x_y.x] = (pos_rot[rel_x_y.x] + (1*rel_x_y.x_val))                  -- relative X axis
			 pos_rot[rel_x_y.y] = (pos_rot[rel_x_y.y] + math.ceil((i*rel_x_y.y_val)*grad))	-- relative Y axis				
			
			
			--new_pos.x = new_pos.x+(math.floor(0.85*i))			
			if minetest.get_node(pos_rot).name == "air" or 
			   minetest.get_node(pos_rot).name == "elepower_lighting:light_fill" then
				
				table.insert(flood_fill_pos,pos_rot) 
				minetest.set_node(pos_rot,{name = "elepower_lighting:light_fill"})
				--minetest.debug(rot_x_y.y..":".. rot_x_y.y_v)

			end							
		end	
		
		meta:set_string("flood_fill_pos", minetest.serialize(flood_fill_pos))
end
---------------------------------------------
--    Removes Flood Light Light nodes      --
---------------------------------------------
function elepower_lighting.remove_flood_light_fill(pos)
	local meta = minetest.get_meta(pos)
	local flood_fill_pos = minetest.deserialize(meta:get_string("flood_fill_pos"))
	
	if type(flood_fill_pos) == "table" then
		meta:set_string("flood_light_pos_s","")
		meta:set_string("flood_light_pos_e","")
		meta:set_string("flood_light_end","")
		for k,pos in pairs(flood_fill_pos) do
			if minetest.get_node(pos).name == "elepower_lighting:light_fill" then
				minetest.remove_node(pos)
			end
		end
	end	
end

-------------------------------------------
-- A rotate and place that allows lights --
--     to mount into wall sockets        --
-- thanks mt forums for below soln idea  --
-------------------------------------------
function elepower_lighting.rot_and_place(itemstack, placer, pointed_thing)
	local p0 = pointed_thing.under
	local p1 = pointed_thing.above
	local param2 = 0

	if placer then
		local placer_pos = placer:get_pos()
		if placer_pos then
			param2 = minetest.dir_to_facedir(vector.subtract(p1, placer_pos))
		end
		
		if p0.x<p1.x then     -- -X
			param2 = 12 + param2
			
		elseif p0.x>p1.x then -- +X
			param2 = 16 + param2
			
		elseif p0.z<p1.z then -- +Z
			param2 = 4 + param2
			
		elseif p0.z>p1.z then -- -Z
			param2 = 8	+ param2
			
		elseif p0.y<p1.y then -- +Y
			param2 = param2
			
		elseif p0.y>p1.y then -- -Y
			param2 = 20 + param2
		end
	end

	return minetest.item_place(itemstack, placer, pointed_thing, param2)
end

-------------------------------------
--      Light State Function       --
-- "Active", "Off", "Out of Power" --
-------------------------------------
function elepower_lighting.status(on_off,storage,usage)
	local status = "Active"
	
		if on_off == 0 then
			status = "Off"
		
		elseif storage < usage then
			status = "Out of Power!"
			
		end
	
	return status
end

------------------------------------
-- Main Lighting timer, what uses --
-- EpU's and allows lights to be  --
--      switched on and off       --
------------------------------------
function elepower_lighting.light_timer(pos)
	local meta        = minetest.get_meta(pos)
	local on_off      = meta:get_int("on_off")
	local reg_name    = minetest.get_node(pos).name
	local node_p2     = minetest.get_node(pos).param2
	local name        = minetest.registered_items[minetest.get_node(pos).name].description
	local light_shape = minetest.registered_items[minetest.get_node(pos).name].ele_light_shape or nil	
	local capacity    = ele.helpers.get_node_property(meta, pos, "capacity")
	local storage     = ele.helpers.get_node_property(meta, pos, "storage")
	local usage       = ele.helpers.get_node_property(meta, pos, "usage")
	local pow_percent = {capacity = capacity, storage = storage, usage = usage}
	local light_strip_axis
	local flood_light_change = false
	
	if light_shape ~= "flood" then
		light_strip_axis = elepower_lighting.p2_to_axis(node_p2)
	
	elseif light_shape == "flood" then
	-- need an overide in the event a wall/tree etc is built infront of an "on" flood light beam
		local flood_light_end = minetest.deserialize(meta:get_string("flood_light_end"))
		local pos_s = minetest.deserialize(meta:get_string("flood_light_pos_s"))
		local pos_e = minetest.deserialize(meta:get_string("flood_light_pos_e"))
		local e_pos
		local bulb_type = string.match(reg_name, ':(.-)_')
		
			if light_shape == "flood" then
				
				-- change floodlight node for angled/tilted version
				local tilt = meta:get_int("tilt") or 0
				local rotate = meta:get_int("rotate") or 0
				local rpn = "p"
				local tpn = "p"
				local new_name
				
				if rotate < 0 then 
					if rotate < -10 then
						rpn = "n"
					end
					rotate = rotate*-1
				end
				
				if tilt < 0 then 
					if tilt < -5 then
						tpn = "n"
					end
					tilt = tilt*-1
				end
				
				if rotate > 10 then
					rotate = 45					
				else
					rotate = 0				
				end
				
				if tilt > 5 then
					tilt = 20
				else
					tilt = 0				
				end
			
				if not string.find(reg_name, "active") then
					new_name = "elepower_lighting:"..bulb_type.."_floodlight_x"..rpn..rotate.."_y"..tpn..tilt				
				else
					new_name = "elepower_lighting:"..bulb_type.."_floodlight_x"..rpn..rotate.."_y"..tpn..tilt.."_active"
				end
				
				if new_name ~= reg_name then
					ele.helpers.swap_node(pos, new_name)
				end
				
			end

		if pos_s then
			local ray = minetest.raycast(pos_s,pos_e,false,true)
			local ray_next = ray:next()	

			while ray_next do
				local name = minetest.get_node(ray_next.under).name
				local node_draw = minetest.registered_items[name].drawtype

				if node_draw ~= "plantlike" and
				   node_draw ~= "firelike" and 
				   node_draw ~= "raillike" and
				   node_draw ~= "torchlike" and
				   node_draw ~= "signlike" and
				   name ~= "elepower_lighting:light_fill" then
					
					e_pos = ray_next.under
					
					break
				end
				ray_next = ray:next()
			end	
			
			if minetest.serialize(e_pos) ~= minetest.serialize(flood_light_end) then
				flood_light_change = true
			end
		end		
	end

	if (storage >= usage and on_off == 1) then
		if not string.find(reg_name, "active") or flood_light_change == true then
					
			if flood_light_change == false then
				ele.helpers.swap_node(pos, reg_name.."_active")
				
			elseif flood_light_change == true then
				elepower_lighting.remove_flood_light_fill(pos)
			end
			
			if light_shape == "flood" then
				elepower_lighting.add_flood_light_fill(pos)
				
			elseif light_shape then
				elepower_lighting.add_remove_light_fill(pos,light_strip_axis,light_shape,1)
			end	

		end	
		
		pow_percent.storage = pow_percent.storage - usage
		storage = pow_percent.storage
		meta:set_int("storage", pow_percent.storage)
	else
		if string.find(reg_name, "active") then
			local name = string.sub(reg_name, 1, -8)
			
			ele.helpers.swap_node(pos, name)
			
			if light_shape then	
				if light_shape == "flood" then
					elepower_lighting.remove_flood_light_fill(pos)
					
				elseif light_shape then			
					elepower_lighting.add_remove_light_fill(pos,light_strip_axis,light_shape)
				end
			end		
		end	
	end

	local status = elepower_lighting.status(on_off,pow_percent.storage,pow_percent.usage)
	meta:set_string("infotext", name.." "..status.."\n" .. ele.capacity_text(capacity, storage))

	if light_shape == "flood" then
		local tilt = meta:get_int("tilt") or 0
		local rotate = meta:get_int("rotate") or 0
		meta:set_string("formspec", get_formspec_flood(pow_percent,tilt,rotate))
	end

	return true
end

---------------------------------------------
-- Main  Colored Lighting timer, what uses --
-- EpU's and allows lights to be switched  -- 
--             on and off                  --
---------------------------------------------
elepower_lighting.colors = {{"#ff0500", "Red"},
							{"#ff3500", "Dark Orange"},
							{"#ff6300", "Orange"},
							{"#ff9100", "Light Orange"},
							{"#ffc000", "Golden"},
							{"#ffef00", "Yellow"},
							{"#e1ff00", "Lemon Lime"},
							{"#b3ff00", "Lime"},
							{"#84ff00", "Lawn Green"},
							{"#56ff00", "Bright Green"},
							{"#00ff36", "Green"},
							{"#00ff65", "Spring Green"},
							{"#00ff93", "Sea Green"},
							{"#00ffc2", "Aqua"},
							{"#00fff0", "Turquoise Blue"},
							{"#00dfff", "Sky Blue"},
							{"#00b1ff", "Vivid Blue"},
							{"#0082ff", "Azure"},
							{"#0053ff", "Blue"},
							{"#0024ff", "Blue Bonnet"},
							{"#0900ff", "Dark Blue"},
							{"#3800ff", "Blue Purple"},
							{"#6700ff", "Indigo"},
							{"#9500ff", "Violet"},
							{"#c400ff", "Orchid"},
							{"#f200ff", "Magenta"},
							{"#ff00dd", "Hot Pink"},
							{"#ff00af", "Shocking Pink"},
							{"#ff0080", "Pink"},
							{"#ff0051", "Apple Red"},
							{"#ffffff", "White"},
							{"#000000", "Black"}
						   }

local function get_formspec_panel_color(power,color_mode,color_sync)	
	local color_m = color_mode
	local color_s = color_sync
	
	if tonumber(color_m) then
		color_m = "Single Color-"..elepower_lighting.colors[(color_m/8)][2]
	
	else
		color_m = color_m:gsub("^%l", string.upper)
	end
	
	local final ="size[8,3]"..
	             "container[0,0.1]"..
				  ele.formspec.power_meter(power)..
				 "container_end[]"..
				 "label[1,-0.05;Current Selection: "..color_m.."]"..
				 "checkbox[6,-0.25;sync;Synchronize;"..color_s.."]"..
				 "image_button[1,0.4;2,0.75;elepower_lighting_gui_rainbow_button.png;r_color;Rainbow;false;true;elepower_lighting_gui_rainbow_button.png^[opacity:127]"..
				 "image_button[1,1.1;2,0.75;elepower_lighting_gui_strobe_button.png;r_color;Strobe;false;true;elepower_lighting_gui_strobe_button.png^[opacity:127]"..
				 "image_button[1,1.8;2,0.75;elepower_lighting_gui_blue_button.png;r_color;Blues;false;true;elepower_lighting_gui_blue_button.png^[opacity:127]"..
				 "image_button[1,2.5;2,0.75;elepower_lighting_gui_red_button.png;r_color;Reds;false;true;elepower_lighting_gui_red_button.png^[opacity:127]"
		
		for k,def in pairs(elepower_lighting.colors) do			
			
			local image_end = "elepower_lighting_gui_color_button.png^[multiply:"..
							  def[1]..";f_color;"..((k)*8)..
							  ";false;true;elepower_lighting_gui_color_button.png^[multiply:"..
							  def[1].."^[opacity:127]]"
							  
			final = final.."style[f_color;font_size=0;textcolor="..def[1].."]"
			if k <= 8 then
				final = final.."image_button["..(3.0+((k-1)*0.6))..",0.4;0.75,0.75;"..image_end
				final = final.."tooltip["..(3.0+((k-1)*0.6))..",0.4;0.55,0.65;"..def[2]..";#30434c;#f9f9f9]"

			elseif k > 8 and k < 17 then
				final = final.."image_button["..(3.0+((k-9)*0.6))..",1.1;0.75,0.75;"..image_end
				final = final.."tooltip["..(3.0+((k-9)*0.6))..",1.1;0.55,0.65;"..def[2]..";#30434c;#f9f9f9]"
				
			elseif k > 16 and k < 25 then 
				final = final.."image_button["..(3.0+((k-17)*0.6))..",1.8;0.75,0.75;"..image_end
				final = final.."tooltip["..(3.0+((k-17)*0.6))..",1.8;0.55,0.65;"..def[2]..";#30434c;#f9f9f9]"				
				
			else
				final = final.."image_button["..(3.0+((k-25)*0.6))..",2.5;0.75,0.75;"..image_end
				final = final.."tooltip["..(3.0+((k-25)*0.6))..",2.5;0.55,0.65;"..def[2]..";#30434c;#f9f9f9]"
			end
			
		end
	
	return final
end

-- register color on_recieve fields
function elepower_lighting.color_on_recieve_fields(pos, formname, fields, player)
	
	local meta = minetest.get_meta(pos)
	
	if fields.quit then
		return
	end
	
	if fields.r_color == "Rainbow" then
		meta:set_string("color_mode","rainbow")
		
	elseif fields.r_color == "Strobe" then
		meta:set_string("color_mode","strobe")
		
	elseif fields.r_color == "Blues" then
		meta:set_string("color_mode","blues")	

	elseif fields.r_color == "Reds" then
		meta:set_string("color_mode","reds")
	
	elseif fields.f_color then
		meta:set_string("color_mode",fields.f_color)
	
	elseif fields.sync then
		meta:set_string("color_sync",tostring(fields.sync))
		
	end
		
	--minetest.debug(dump(fields))	
end

function elepower_lighting.light_timer_colored(pos)
	local meta        = minetest.get_meta(pos)
	local on_off      = meta:get_int("on_off")
	local cycles      = meta:get_int("light_color_count")
	local color_mode  = meta:get_string("color_mode") or "rainbow"
	local color_sync  = meta:get_string("color_sync") or "false"
	local run_bwd     = meta:get_string("run_bwd") or "false"
	local node        = minetest.get_node(pos)
	local name        = minetest.registered_items[minetest.get_node(pos).name].description
	local reg_name    = minetest.get_node(pos).name
	local capacity    = ele.helpers.get_node_property(meta, pos, "capacity")
	local storage     = ele.helpers.get_node_property(meta, pos, "storage")
	local usage       = ele.helpers.get_node_property(meta, pos, "usage")
	local pow_percent = {capacity = capacity, storage = storage, usage = usage}
	local strobe_ok   = true
	local is_timer    = true

	
	if cycles == 5 then   --(1 second)
		if (storage >= usage and on_off == 1) then
			if not string.find(reg_name, "active") and color_mode ~= "strobe" then
				ele.helpers.swap_node(pos, reg_name.."_active")
				
			end	
						
			pow_percent.storage = pow_percent.storage - usage
			storage = pow_percent.storage
			meta:set_int("storage", pow_percent.storage)
		else
			if string.find(reg_name, "active") then
				local name = string.sub(reg_name, 1, -8)
				ele.helpers.swap_node(pos, name)
				strobe_ok = false
						
			end	
		end
		local status = elepower_lighting.status(on_off,pow_percent.storage,pow_percent.usage)
		
		meta:set_string("formspec", get_formspec_panel_color(pow_percent,color_mode,color_sync))			
		meta:set_string("infotext", name .." "..status.. "\n" .. ele.capacity_text(capacity, storage))

		cycles = 0
	end
	
	node = minetest.get_node(pos)
	
	if string.find(node.name, "active") or strobe_ok then
			
		if color_mode == "rainbow" then
		
			if color_sync == "true" then
				local sync_total = 30
				local node_plain_p2 = node.param2 % 8
				
				col_seq = math.ceil(sync_total*((((elepower_lighting.timer/0.2))/sync_total)%1))
				node.param2 = node_plain_p2 + ((col_seq*8)-8)
				minetest.swap_node(pos, node)
				
			else
				node.param2 = node.param2+8
				
				if node.param2 >=240 then
					node.param2 = (node.param2 % 32)
				end
				
				minetest.swap_node(pos, node)
			end
			
		elseif color_mode == "blues" or color_mode == "reds"  then		
			local blues_seq_p2  = {120,128,136,144,152,160,168}
			local reds_seq_p2   = {200,208,216,224,232,0}
			local node_plain_p2 = node.param2 % 8
			local cur_color_p2  = math.floor(node.param2/8)*8
			local col_seq       = 1
			local change        = 1
			local col_seq_p2    = blues_seq_p2
			local sync_total    = #blues_seq_p2-1
			
			if color_mode == "reds" then
				col_seq_p2 = reds_seq_p2
				sync_total = #reds_seq_p2-1
			end
			
			if color_sync == "true" then			
				if math.floor(((elepower_lighting.timer/0.2)/sync_total)%2) == 0 then
					--minetest.debug("bwd: ".. (sync_total+1)-math.ceil(sync_total*((((elepower_lighting.timer/0.2))/sync_total)%1)))
					col_seq = (sync_total+1)-math.ceil(sync_total*((((elepower_lighting.timer/0.2))/sync_total)%1))
					change = 0
					meta:set_string("run_bwd", "true")
					
				else
					--minetest.debug("fwd: ".. 1+math.ceil(sync_total*((((elepower_lighting.timer/0.2))/sync_total)%1)))
					col_seq = 1+math.ceil(sync_total*((((elepower_lighting.timer/0.2))/sync_total)%1))
					change = 0
					meta:set_string("run_bwd", "false")
				end

			else
				for k,v in pairs(col_seq_p2 ) do
					if v == cur_color_p2 then
						col_seq = k
					end			
				end
						
				if (col_seq == #col_seq_p2  or run_bwd == "true") and col_seq ~= 1 then
					meta:set_string("run_bwd", "true")					
					change = -1
					
				elseif col_seq == 1 then
					meta:set_string("run_bwd", "false")
				end	
			end
			
			--minetest.debug(col_seq+change)
			node.param2 = col_seq_p2[col_seq+change] + node_plain_p2
			minetest.swap_node(pos, node)
		
		elseif color_mode == "strobe" then
			
			if color_sync == "true" then
				
				local col_seq = math.ceil(math.floor((elepower_lighting.timer/0.2)+0.5)%2)
				
				if col_seq == 1 then					
					if not string.find(reg_name, "active") then
						ele.helpers.swap_node(pos, reg_name.."_active")
					end
				
				else				
					if string.find(reg_name, "active") then
						local name = string.sub(reg_name, 1, -8)
						ele.helpers.swap_node(pos, name)
					end
				end
			
			else
			
				if string.find(reg_name, "active") then
					local name = string.sub(reg_name, 1, -8)
					ele.helpers.swap_node(pos, name)
				
				else
					ele.helpers.swap_node(pos, reg_name.."_active")
				end
			end
		
		elseif type(tonumber(color_mode)) == "number" then
		
			local node_plain_p2 = node.param2 % 8
			local cur_color_p2  = math.floor(node.param2/8)*8
			
			if color_mode-8 ~= cur_color_p2 then
				node.param2 = color_mode-8 + node_plain_p2
				minetest.swap_node(pos, node)			
			end
				
		else
			-- catch error state set to white
			local node_plain_p2 = node.param2 % 8
			node.param2 = node_plain_p2 + 240
			minetest.swap_node(pos, node)
		end
		
		
	end
	
	local timer = minetest.get_node_timer(pos)
	
	if timer:get_timeout() ~= 0.2 then	
		timer:start(0.2)
		is_timer = false
	end
		
	meta:set_int("light_color_count",cycles+1)	
	
		
	return is_timer
end

elepower_lighting.timer = 0
minetest.register_globalstep(function(dtime)
	-- note counter shouldn't cause an issue until uptime exceeds about 7million yrs
	elepower_lighting.timer = elepower_lighting.timer + dtime;
	
end)

-----------------------------------------
-- Lighting simple functions for basic --
--         node functionality          --
-----------------------------------------
-- set light on/off by punch
function elepower_lighting.light_punch(pos,player)
	local meta   = minetest.get_meta(pos)
	local on_off = meta:get_int("on_off") or 1
	
	if on_off == 1 then
		on_off = 0
		
	else
		on_off = 1
	end
	meta:set_int("on_off",on_off)
end

-- set lights to on when constructed
function elepower_lighting.light_construct(pos)
	local meta  = minetest.get_meta(pos)
	meta:set_int("on_off",1)
	meta:set_string("infotext", "Active")
	
	local is_colored  = minetest.registered_items[minetest.get_node(pos).name].palette or nil
	
	if is_colored then
		meta:set_string("color_mode","rainbow")
		local timer = minetest.get_node_timer(pos)
		timer:start(0.2)
	end
	
end

-- Main place function
function elepower_lighting.light_place(itemstack, placer, pointed_thing)
	if pointed_thing.type ~= "node" then
		return itemstack
	end

	return elepower_lighting.rot_and_place(itemstack, placer, pointed_thing)
end

-- For lights more than 1x1 cleanup light_fill on destruction
function elepower_lighting.light_strip_cleanup(pos)

		local node_p2  = minetest.get_node(pos).param2
		local light_shape = minetest.registered_items[minetest.get_node(pos).name].ele_light_shape or nil			
		local light_strip_axis = elepower_lighting.p2_to_axis(node_p2)	
		
		if light_shape == "flood" then
			elepower_lighting.remove_flood_light_fill(pos)
			
		else
			elepower_lighting.add_remove_light_fill(pos,light_strip_axis,light_shape)
		end
		
	end