local MT = minetest
local vMod = vm_lighting_wand

local player_power = {}

local max_power = 0

-- Set the max power (set from levels)
vMod.set_max_power = function(amount)
  max_power = amount or max_power
end

vMod.get_max_power = function()
  return max_power
end

-- Sets players power to the given amount or max_power
vMod.set_power = function(player, amount)
  if not player or not amount or amount < 0 then
    return
  end
  local meta = player:get_meta()
  amount = vMod.round(amount)
  amount = amount >= 0 and amount or 0
  amount = amount <= max_power and amount or max_power
  meta:set_int(vMod.modname .. "_power", amount)
  player_power[player:get_player_name()] = amount
end

-- Get a players power
vMod.get_power = function(player)
  if not player then
    return 0
  end
  return player_power[player:get_player_name()] or vMod.get_real_power(player)
end

-- really get a players power not ust the cache
vMod.get_real_power = function(player)
  if not player then
    return 0
  end
  local power = player:get_meta():get_int(vMod.modname .. "_power") or 0
  player_power[player:get_player_name()] = power
  return power
end

-- Add an amount to a player power
vMod.add_power = function(player, amount)
  if not player or not amount or amount <= 0 then
    return
  end
  local power = vMod.get_power(player)
  local sum = power + amount
  vMod.set_power(player, sum)
end

-- Remove an amount from a players power
vMod.remove_power = function(player, amount)
  if not player or not amount or amount <= 0 then
    return
  end
  local power = vMod.get_power(player)
  local sum = power - amount
  vMod.set_power(player, sum)
end

-- Test if the player has enough power for the given amount
vMod.can_output_power = function(player, amount)
  if not player or not amount or amount < 0 then
    return false
  end

  if vMod.is_creative_mode(player) then
    return true
  end

  if vMod.get_power(player) >= amount then
    return true
  end

  return false
end

-- Test if the player can store the given amount
vMod.can_input_power = function(player, amount)
  if not player or not amount or amount <= 0 then
    return 0
  end
  local free = max_power - vMod.get_power(player)
  if free <= 0 then
    free = 0
  end
  if free >= amount then
    return amount
  end
  return free
end

-- Works out the cost of placing a node
vMod.get_power_cost = function(player, to_pos, removal)
  if not player or not to_pos then
    return false
  end
  if vMod.is_creative_mode(player) then
    return 0
  end

  removal = removal or false
  local cost = player:get_pos()
  local level = vMod.get_level(player)
  local from, to, p
  for key, value in pairs(cost) do
    p = to_pos[key]
    from = value < 0 and value * -1 or value
    to = p < 0 and p * -1 or p
    cost[key] = vMod.round(to - from)
  end
  local sum = cost.x + cost.z + cost.y
  sum = sum * level.cost_per_node / 3
  if not removal then
    return vMod.round(sum + level.cost_per_use)
  else
    return vMod.round((sum / level.removal_reduction) + level.cost_per_use)
  end
end

-- Will apply a charge to the players power if it can - returns true/false
vMod.do_power_cost = function(player, to_pos, removal)
  -- skip everything if the player is in creative mode
  if vMod.is_creative_mode(player) then
    return true
  end
  local cost = vMod.get_power_cost(player, to_pos, removal)
  if cost == false then
    return false
  end

  -- if the player doesnt have enough power
  if not vMod.can_output_power(player, cost) then
    return false
  end

  -- charge the player
  vMod.remove_power(player, cost)
  return true
end

MT.register_on_joinplayer(
  function(player)
    local power = vMod.get_power(player)
    if power > max_power then
      power = max_power
      vMod.set_power(player, power)
    end
  end
)

MT.register_on_leaveplayer(
  function(player)
    player_power[player:get_player_name()] = nil
  end
)
