-- TODO: Bring electricity back one day.

PyuTestCore.ELECTRICITY_UPDATE_TIME = 0.1

local function set_electrified(pos, value)
  local meta = minetest.get_meta(pos)
  if value then
    meta:set_int("electrified", 1)
  else
    meta:set_int("electrified", 0)
  end
end

local function get_electrified(pos)
  local meta = minetest.get_meta(pos)
  return meta:get_int("electrified") == 1 and true or false
end

local function set_powered(pos, value)
  local meta = minetest.get_meta(pos)
  if value then
    meta:set_int("powered", 1)
  else
    meta:set_int("powered", 0)
  end
end

local function get_powered(pos)
  local meta = minetest.get_meta(pos)
  return meta:get_int("powered") == 1 and true or false
end

local function set_negated(pos, value)
  local meta = minetest.get_meta(pos)
  if value then
    meta:set_int("negated", 1)
  else
    meta:set_int("negated", 0)
  end
end

local function get_negated(pos)
  local meta = minetest.get_meta(pos)
  return meta:get_int("negated") == 1 and true or false
end

local function is_electrified(pos, log)
  local positions = {
    vector.new(pos.x + 1, pos.y, pos.z),
    vector.new(pos.x - 1, pos.y, pos.z),
    vector.new(pos.x, pos.y + 1, pos.z),
    vector.new(pos.x, pos.y - 1, pos.z),
    vector.new(pos.x, pos.y, pos.z + 1),
    vector.new(pos.x, pos.y, pos.z - 1)
  }

  local result = false
  for _, v in pairs(positions) do
    local powered = get_powered(v)
    local electrified = get_electrified(v)
    local negated = get_negated(v)
    if log then minetest.log(string.format("Powered: %s", tostring(powered))) end
    if log then minetest.log(string.format("Negated: %s", tostring(negated))) end

    if powered then
      return true
    end

    if electrified and not negated then
      result = true
      break
    end

    if not electrified and negated then
      result = true
      break
    end
  end

  return result
end


PyuTestCore.make_node("pyutest_core:copper_wire", "Copper Wire", {
    block = PyuTestCore.BLOCK_BREAKABLE_INSTANT
}, {"wire.png"}, {
    drawtype = "signlike",
    paramtype = "light",
    sunlight_propagates = true,
    color = "darkgoldenrod",
    walkable = false,
    inventory_image = "wire.png",
    paramtype2 = "wallmounted",
    selection_box = {
      type = "wallmounted"
    },

    on_construct = function (pos)
      set_powered(pos, false)
      local timer = minetest.get_node_timer(pos)
      timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
    end,

    on_timer = function (pos)
      if is_electrified(pos) then
	set_electrified(pos, true)
      else
	set_electrified(pos, false)
      end

      local timer = minetest.get_node_timer(pos)
      timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
    end
})

minetest.register_craft({
    output = "pyutest_core:copper_wire 16",
    recipe = {
      "pyutest_core:copper_ingot"
    },
    type = "shapeless"
})

PyuTestCore.make_node("pyutest_core:negator", "Negated Copper Wire", {
    block = PyuTestCore.BLOCK_BREAKABLE_INSTANT
}, {"wire.png"}, {
    drawtype = "signlike",
    paramtype = "light",
    sunlight_propagates = true,
    color = "yellowgreen",
    walkable = false,
    inventory_image = "wire.png",
    paramtype2 = "wallmounted",
    selection_box = {
      type = "wallmounted"
    },

    on_construct = function (pos)
      set_negated(pos, true)
      set_powered(pos, false)
      local timer = minetest.get_node_timer(pos)
      timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
    end,

    on_timer = function (pos)
      if is_electrified(pos) then
	set_electrified(pos, true)
      else
	set_electrified(pos, false)
      end

      local timer = minetest.get_node_timer(pos)
      timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
    end
})

PyuTestCore.make_node("pyutest_core:switch", "Switch", {
    block = PyuTestCore.BLOCK_BREAKABLE_NORMAL
}, {"device.png"}, {
    color = "dimgray",
    on_construct = function(pos)
      set_powered(pos, false)
    end,

    on_rightclick = function(pos)
      set_powered(pos, not get_powered(pos))
    end
})

PyuTestCore.make_device = function (name, desc, color, craftitem, action, setup, extra_conf)
  PyuTestCore.make_node(name.."_device", desc, {
      block = PyuTestCore.BLOCK_BREAKABLE_NORMAL
  }, {"device.png"}, PyuTestCore.util.tableconcat({
	color = color,
	on_construct = function (pos)
	  local s = setup or function (_) end
	  s(pos)

	  local timer = minetest.get_node_timer(pos)
	  timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
	end,
	on_timer = function (pos)
	  if is_electrified(pos, true) then
	    action(true, pos)
	  else
	    action(false, pos)
	  end

	  local timer = minetest.get_node_timer(pos)
	  timer:start(PyuTestCore.ELECTRICITY_UPDATE_TIME)
	end
  }, extra_conf or {}))

  minetest.register_craft({
      output = name.."_device 4",
      recipe = {
	{"pyutest_core:copper_ingot", "pyutest_core:copper_ingot", "pyutest_core:copper_ingot"},
	{"pyutest_core:copper_ingot", craftitem, "pyutest_core:copper_ingot"},
	{"pyutest_core:copper_ingot", "pyutest_core:copper_ingot", "pyutest_core:copper_ingot"}
      }
  })
end

PyuTestCore.make_device("pyutest_core:time", "Time Device", "orange", "pyutest_core:light", function (e)
    if not e then
      minetest.chat_send_all("Not electrified!")
      return
    end
    minetest.chat_send_all(string.format("Time: " .. os.date("%I:%M:%S", os.time())))
end)

PyuTestCore.make_device("pyutest_core:block_setter", "Block Setter Device", "blue", "pyutest_core:stone_block", function (e, pos)
    if not e then return end
    local blocks = {}
    for k, _ in pairs(minetest.registered_nodes) do
      local no_disallowed_blocks_match = (k ~= "ignore" and k ~= "pyutest_core:contagious_acid")

      if no_disallowed_blocks_match then
	table.insert(blocks, k)
      end
    end
    local pos = vector.new(pos.x, pos.y + 1, pos.z)
    minetest.remove_node(pos)
    minetest.place_node(pos, {name = blocks[math.random(#blocks)]})
end)

PyuTestCore.make_device("pyutest_core:freezer", "Freezer Device", "skyblue", "pyutest_core:ice_block", function(e, pos)
    if not e then return end

    PyuTestCore.dorange(pos, 3, function(p)
	local node = minetest.get_node_or_nil(p)
	if node == nil then return end

	if minetest.get_item_group(node.name, "water") ~= 0 then
	  minetest.set_node(p, {name = "pyutest_core:ice_block"})
	elseif minetest.get_item_group(node.name, "lava") ~= 0 then
	  minetest.set_node(p, {name = "pyutest_core:hellstone_block"})
	end
    end)
end)

PyuTestCore.make_device("pyutest_core:heater", "Heater Device", "maroon", "pyutest_core:ash", function(e, pos)
    if not e then return end

    PyuTestCore.dorange(pos, 3, function(p)
	local node = minetest.get_node_or_nil(p)
	if node == nil then return end

	if minetest.get_item_group(node.name, "ice") ~= 0 then
	  minetest.set_node(p, {name = "pyutest_core:water_source"})
	end
    end)
end)
