--[[

	TechAge
	=======

	Copyright (C) 2017-2022 Joachim Stolberg

	AGPL v3
	See LICENSE.txt for more information

	TA4 Collector
	Collects states from other nodes, acting as a state concentrator.

]]--

-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local NDEF = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}) end
local logic = techage.logic

local CYCLE_TIME = 1

-- The numbering seems strange here, but I had to add the "running" state
-- afterwards without changing the behavior of the block.
local tStates = {stopped = 0, running = 1, standby = 2, blocked = 3, fault = 4, defect = 5}
local tDropdownPos = {["1 standby"] = 1, ["2 blocked"] = 2, ["3 fault"] = 3, ["4 defect"] = 4}
local lStates = {[0] = "stopped", "running", "standby", "blocked", "fault", "defect"}
local tDropdownPos = {["1 standby"] = 1, ["2 blocked"] = 2, ["3 nopower"] = 3, ["4 fault"] = 4}
local TaStates = {running = 1, blocked = 2, standby = 3, nopower = 4, fault = 5, stopped = 6}

local function formspec(nvm, meta)
	nvm.poll_numbers = nvm.poll_numbers or {}
	local poll_numbers = table.concat(nvm.poll_numbers, " ")
	local event_number = meta:get_string("event_number")
	local dropdown_pos = meta:get_int("dropdown_pos")
	if dropdown_pos == 0 then dropdown_pos = 1 end

	return "size[9,6]"..
		default.gui_bg..
		default.gui_bg_img..
		default.gui_slots..
		"field[0.3,0.6;9,1;poll_numbers;"..S("Node numbers to read the states from")..":;"..poll_numbers.."]" ..
		"field[0.3,2;9,1;event_number;"..S("Node number to send the events to")..":;"..event_number.."]" ..
		"label[1.3,2.8;"..S("Send an event if state is equal or larger than")..":]"..
		"dropdown[1.2,3.4;7,4;severity;1 standby,2 blocked,3 nopower,4 fault;"..dropdown_pos.."]"..
		"button_exit[3,5;2,1;exit;Save]"
end


local function send_event(nvm, meta)
	local event_number = meta:get_string("event_number")
	if event_number ~= "" then
		local severity = meta:get_int("dropdown_pos")
		local own_number = meta:get_string("own_number")
		if nvm.common_state > severity then
			techage.send_multi(own_number, event_number, "on")
		else
			techage.send_multi(own_number, event_number, "off")
		end
	end
end

local function request_state(nvm, meta)
	local number = nvm.poll_numbers and nvm.poll_numbers[nvm.idx]
	if number then
		local own_number = meta:get_string("own_number")
		local state = techage.send_single(own_number, number, "state", nil)
		if state then
			state = tStates[state] or 0
			nvm.common_state = math.max(nvm.common_state, state)
		end
	end
end


local function on_timer(pos,elapsed)
	local nvm = techage.get_nvm(pos)
	local meta = minetest.get_meta(pos)
	nvm.idx = (nvm.idx or 0) + 1
	nvm.common_state = nvm.common_state or 0

	if not nvm.poll_numbers then
		local own_number = meta:get_string("own_number")
		meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": stopped")
		nvm.common_state = 0
		nvm.idx = 1
		return false
	end

	if nvm.idx > #nvm.poll_numbers then
		nvm.idx = 1
		if nvm.stored_state ~= nvm.common_state then
			send_event(nvm, meta)
			local own_number = meta:get_string("own_number")
			meta:set_string("infotext", S("TA4 State Collector").." "..own_number..': "'..lStates[nvm.common_state]..'"')
			nvm.stored_state = nvm.common_state
		end
		nvm.common_state = 0  -- reset for the next round
	end

	request_state(nvm, meta)
	return true
end

minetest.register_node("techage:ta4_collector", {
	description = S("TA4 State Collector"),
	inventory_image = "techage_smartline_collector_inv.png",
	tiles = {
		-- up, down, right, left, back, front
		"techage_smartline.png",
		"techage_smartline.png",
		"techage_smartline.png",
		"techage_smartline.png",
		"techage_smartline.png",
		"techage_smartline.png^techage_smartline_collector.png",
	},

	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {
			{ -6/32, -6/32, 14/32,  6/32,  6/32, 16/32},
		},
	},

	after_place_node = function(pos, placer)
		local nvm = techage.get_nvm(pos)
		local meta = minetest.get_meta(pos)
		local own_number = techage.add_node(pos, "techage:ta4_collector")
		meta:set_string("own_number", own_number)
		meta:set_string("formspec", formspec(nvm, meta))
		meta:set_string("infotext", S("TA4 State Collector").." "..own_number)
		meta:set_string("owner", placer:get_player_name())
	end,

	on_receive_fields = function(pos, formname, fields, player)
		local meta = minetest.get_meta(pos)
		local owner = meta:get_string("owner")
		if owner ~= player:get_player_name() then
			return
		end

		local nvm = techage.get_nvm(pos)
		local timer = minetest.get_node_timer(pos)
		local own_number = meta:get_string("own_number")

		if fields.quit == "true" and fields.poll_numbers then
			if techage.check_numbers(fields.event_number, player:get_player_name()) then
				meta:set_string("event_number", fields.event_number)
			end
			if techage.check_numbers(fields.poll_numbers, player:get_player_name()) then
				nvm.poll_numbers = string.split(fields.poll_numbers, " ")
				nvm.idx = 0
				if not timer:is_started() then
					timer:start(CYCLE_TIME)
				end
				meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": running")
			else
				if timer:is_started() then
					timer:stop()
				end
				meta:set_string("infotext", S("TA4 State Collector").." "..own_number..": stopped")
				nvm.common_state = 0
				nvm.stored_state = 0
			end
			if fields.severity then
				meta:set_int("dropdown_pos", tDropdownPos[fields.severity])
			end
			meta:set_string("formspec", formspec(nvm, meta))
		end
	end,

	techage_set_numbers = function(pos, numbers, player_name)
		local nvm = techage.get_nvm(pos)
		local meta = M(pos)
		local res = logic.set_numbers(pos, numbers, player_name, NDEF(pos).description)
		meta:set_string("formspec", formspec(nvm, meta))
		return res
	end,

	on_timer = on_timer,

	after_dig_node = function(pos, oldnode, oldmetadata)
		techage.remove_node(pos, oldnode, oldmetadata)
	end,

	paramtype = "light",
	sunlight_propagates = true,
	paramtype2 = "facedir",
	groups = {choppy=2, cracky=2, crumbly=2},
	is_ground_content = false,
	sounds = default.node_sound_metal_defaults(),
})


minetest.register_craft({
	output = "techage:ta4_collector",
	recipe = {
		{"", "techage:aluminum", "dye:blue"},
		{"", "default:mese_crystal_fragment", "techage:ta4_wlanchip"},
	},
})

techage.register_node({"techage:ta4_collector"}, {
	on_recv_message = function(pos, src, topic, payload)
		if topic == "state" then
			local nvm = techage.get_nvm(pos)
			return lStates[nvm.stored_state or 0]
		else
			return "unsupported"
		end
	end,
	on_beduino_request_data = function(pos, src, topic, payload)
		if topic == 129 then
			local nvm = techage.get_nvm(pos)
			return 0, {TaStates[lStates[nvm.stored_state or 0]]}
		else
			return 2, ""
		end
	end,
	on_node_load = function(pos)
		minetest.get_node_timer(pos):start(CYCLE_TIME)
	end,
})
