-- Bundled by luabundle {"version":"1.6.0"}
local __bundle_require, __bundle_loaded, __bundle_register, __bundle_modules = (function(superRequire)
	local loadingPlaceholder = {[{}] = true}

	local register
	local modules = {}

	local require
	local loaded = {}

	register = function(name, body)
		if not modules[name] then
			modules[name] = body
		end
	end

	require = function(name)
		local loadedModule = loaded[name]

		if loadedModule then
			if loadedModule == loadingPlaceholder then
				return nil
			end
		else
			if not modules[name] then
				if not superRequire then
					local identifier = type(name) == 'string' and '\"' .. name .. '\"' or tostring(name)
					error('Tried to require ' .. identifier .. ', but no such module has been registered')
				else
					return superRequire(name)
				end
			end

			loaded[name] = loadingPlaceholder
			loadedModule = modules[name](require, loaded, register, modules)
			loaded[name] = loadedModule
		end

		return loadedModule
	end

	return require, loaded, register, modules
end)(nil)
__bundle_register("__root", function(require, _LOADED, __bundle_register, __bundle_modules)
require("accessories/CleanUpHelper")
end)
__bundle_register("accessories/CleanUpHelper", function(require, _LOADED, __bundle_register, __bundle_modules)
--[[
Cleans up the table for the next scenario in a campaign:
- sets counters to default values (resources and doom) or trauma values (health and sanity, if not disabled) from campaign log
- puts everything on playmats and hands into respective trashcans
- use the IGNORE_TAG to exclude objects from tidying (default: "CleanUpHelper_Ignore")
--]]

local tokenSpawnTrackerApi = require("core/token/TokenSpawnTrackerApi")

-- enable this for debugging
local SHOW_RAYS = false

-- these objects will be ignored
local IGNORE_GUIDS = {
  -- big playmat, change image panel and investigator counter
  "b7b45b"; "f182ee"; "721ba2";
  -- bless/curse manager
  "afa06b"; "bd0253"; "5933fb";
  -- stuff on agenda/act playmat
  "85c4c6"; "4a3aa4"; "fea079"; "b015d8"; "11e0cf"; "9f334f"; "70b9f6"; "0a5a29";
  -- doom/location token bag
  "47ffc3"; "170f10";
  -- table
  "4ee1f2"
}

-- objects with this tag will be ignored
local IGNORE_TAG = "CleanUpHelper_ignore"

-- colors and order for following tables
local COLORS = { "White"; "Orange"; "Green"; "Red"; "Agenda" }

-- counter GUIDS (4x damage and 4x horror)
local DAMAGE_HORROR_GUIDS = {
  "eb08d6"; "e64eec"; "1f5a0a"; "591a45";
  "468e88"; "0257d9"; "7b5729"; "beb964";
}

local RESET_VALUES = {}

-- GUIDS of objects (in order of ownership relating to 'COLORS')
local PLAYERMAT_GUIDS    = { "8b081b"; "bd0ff4"; "383d8b"; "0840d5" }
local RESOURCE_GUIDS     = { "4406f0"; "816d84"; "cd15ac"; "a4b60d" }
local TRACKER_GUIDS      = { "e598c2"; "b4a5f7"; "af7ed7"; "e74881" }
local CLUE_GUIDS         = { "d86b7c"; "1769ed"; "032300"; "37be78" }
local CLUE_CLICKER_GUIDS = { "db85d6"; "3f22e5"; "891403"; "4111de" }
local TRASHCAN_GUIDS     = { "147e80"; "f7b6c8"; "5f896a"; "4b8594"; "70b9f6" }

-- values for physics.cast (4 entries for player zones, 5th entry for agenda/act deck, 6th for campaign log)
local PHYSICS_POSITION = {
  { -54.5, 2, 21 };
  { -54.5, 2, -21 };
  { -25.0, 2, 26 };
  { -25.0, 2, -26 };
  { -02.0, 2, 10 };
  { -00.0, 2, -27 }
}

local PHYSICS_ROTATION = { 270, 270, 0, 180, 270, 0 }

local PHYSICS_SCALE = {
  { 36.6, 1, 14.5 };
  { 36.6, 1, 14.5 };
  { 28.0, 1, 14.5 };
  { 28.0, 1, 14.5 };
  { 55.0, 1, 13.5 };
  { 05.0, 1, 05.0 }
}

local optionsVisible        = false
local options               = {}
options["importTrauma"]     = true
options["tidyPlayermats"]   = true
options["removeDrawnLines"] = false

local buttonParameters          = {}
buttonParameters.function_owner = self

---------------------------------------------------------
-- option loading and GUI setup
---------------------------------------------------------

function onSave()
  return JSON.encode({
    options = options
  })
end

function onLoad(savedData)
  if savedData ~= nil then
    local loadedData = JSON.decode(savedData)
    options = loadedData.options
    -- update UI to match saved state
    for id, state in pairs(options) do
      self.UI.setAttribute(id, "image", state and "option_on" or "option_off")
    end
  end

  -- index 0: button as label
  buttonParameters.label          = "Clean Up Helper"
  buttonParameters.click_function = "none"
  buttonParameters.position       = { x = 0, y = 0.1, z = -1.3 }
  buttonParameters.height         = 0
  buttonParameters.width          = 0
  buttonParameters.font_size      = 230
  buttonParameters.font_color     = Color(0, 0, 0)
  self.createButton(buttonParameters)

  -- index 1: option button
  buttonParameters.label          = "Settings"
  buttonParameters.click_function = "showOrHideOptions"
  buttonParameters.color          = { 0, 0, 0, 0.96 }
  buttonParameters.position.z     = -0.1
  buttonParameters.height         = 350
  buttonParameters.width          = 1000
  buttonParameters.font_size      = 190
  buttonParameters.font_color     = "White"
  self.createButton(buttonParameters)

  -- index 2: start button
  buttonParameters.label          = "Reset play areas"
  buttonParameters.click_function = "cleanUp"
  buttonParameters.position.z     = 1.1
  buttonParameters.width          = 1550
  self.createButton(buttonParameters)

  -- create single table for ignoring
  for _, v in ipairs(CLUE_GUIDS) do table.insert(IGNORE_GUIDS, v) end
  for _, v in ipairs(CLUE_CLICKER_GUIDS) do table.insert(IGNORE_GUIDS, v) end
  for _, v in ipairs(RESOURCE_GUIDS) do table.insert(IGNORE_GUIDS, v) end
  for _, v in ipairs(TRASHCAN_GUIDS) do table.insert(IGNORE_GUIDS, v) end
  for _, v in ipairs(PLAYERMAT_GUIDS) do table.insert(IGNORE_GUIDS, v) end
  for _, v in ipairs(DAMAGE_HORROR_GUIDS) do table.insert(IGNORE_GUIDS, v) end
end

---------------------------------------------------------
-- click functions for option buttons
---------------------------------------------------------

-- changes the UI state and the internal variable for the togglebuttons
function optionButtonClick(_, id)
  local currentState = options[id]
  local newState = (currentState and "option_off" or "option_on")
  options[id] = not currentState
  self.UI.setAttribute(id, "image", newState)
end

-- shows or hides the option panel
function showOrHideOptions()
  optionsVisible = not optionsVisible

  if optionsVisible then
    self.UI.show("options")
  else
    self.UI.hide("options")
  end
end

---------------------------------------------------------
-- main function
---------------------------------------------------------

function cleanUp(_, color)
  printToAll("------------------------------", "White")
  printToAll("Clean up started!", "Orange")
  printToAll("Resetting counters...", "White")

  ignoreCustomDataHelper()
  getTrauma()
  updateCounters(DAMAGE_HORROR_GUIDS, RESET_VALUES, "Damage / Horror")
  updateCounters(RESOURCE_GUIDS, 5, "Resources")
  updateCounters(CLUE_CLICKER_GUIDS, 0, "Clue clickers")
  resetSkillTrackers()
  resetDoomCounter()
  removeBlessCurse(color)
  removeLines()
  discardHands()
  tokenSpawnTrackerApi.resetAll()

  printToAll("Tidying main play area...", "White")
  startLuaCoroutine(self, "tidyPlayareaCoroutine")
end

---------------------------------------------------------
-- modular functions, called by other functions
---------------------------------------------------------

function updateCounters(tableOfGUIDs, tableOfNewValues, info)
  if tonumber(tableOfNewValues) then
    local value = tableOfNewValues
    tableOfNewValues = {}
    for i = 1, #tableOfGUIDs do
      table.insert(tableOfNewValues, value)
    end
  end

  for i, guid in ipairs(tableOfGUIDs) do
    local TOKEN = getObjectFromGUID(guid)

    if TOKEN ~= nil then
      TOKEN.call("updateVal", tableOfNewValues[i])
    else
      printToAll(info .. ": No. " .. i .. " could not be found.", "Yellow")
    end
  end
end

-- set investigator skill trackers to "1, 1, 1, 1"
function resetSkillTrackers()
  for i, guid in ipairs(TRACKER_GUIDS) do
    local obj = getObjectFromGUID(guid)

    if obj ~= nil then
      obj.call("updateStats", { 1, 1, 1, 1 })
    else
      printToAll("Skill tracker number " .. i .. " could not be found.", "Yellow")
    end
  end
end

-- reset doom on agenda
function resetDoomCounter()
  local doomcounter = getObjectFromGUID("85c4c6")

  if doomcounter ~= nil then
    doomcounter.call("updateVal")
  else
    printToAll("Doom counter could not be found.", "Yellow")
  end
end

-- gets the GUID of a custom data helper (if present) and adds it to the ignore list
function ignoreCustomDataHelper()
  local playArea = getObjectFromGUID("721ba2")
  local customDataHelper = playArea.getVar("customDataHelper")
  if customDataHelper then table.insert(IGNORE_GUIDS, customDataHelper.getGUID()) end
end

-- read values for trauma from campaign log if enabled
function getTrauma()
  RESET_VALUES = {
    0; 0; 0; 0;
    0; 0; 0; 0
  }

  -- stop here if trauma import is disabled
  if not options["importTrauma"] then
    printToAll("Default values for health and sanity loaded.", "Yellow")
    return
  end

  -- get campaign log
  local campaignLog = findObjects(6)[1]
  if campaignLog == nil then
    printToAll("Campaign log not found in standard position!", "Yellow")
    printToAll("Default values for health and sanity loaded.", "Yellow")
    return
  end

  -- get data from campaign log if possible
  local counterData = campaignLog.hit_object.getVar("ref_buttonData")
  if counterData ~= nil then
    printToAll("Trauma values found in campaign log!", "Green")
    for i = 1, 10, 3 do
      RESET_VALUES[1 + (i - 1) / 3] = counterData.counter[i].value
      RESET_VALUES[5 + (i - 1) / 3] = counterData.counter[i + 1].value
    end
  else
    printToAll("Trauma values could not be found in campaign log!", "Yellow")
    printToAll("Default values for health and sanity loaded.", "Yellow")
  end
end

-- get rid of bless/curse tokens via bless/curse manager
function removeBlessCurse(color)
  local BlessCurseManager = getObjectFromGUID("5933fb")

  if BlessCurseManager ~= nil then
    BlessCurseManager.call("doRemove", color)
  else
    printToAll("Bless / Curse manager could not be found and thus bless/curse tokens were skipped.", "Yellow")
  end
end

-- remove drawn lines
function removeLines()
  if options["removeDrawnLines"] then
    printToAll("Removing vector lines...", "White")
    Global.setVectorLines({})
  end
end

-- discard all hand objects
function discardHands()
  if not options["tidyPlayermats"] then return end
  for i = 1, 4 do
    local trashcan = getObjectFromGUID(TRASHCAN_GUIDS[i])
    if trashcan == nil then return end
    local hand = Player[COLORS[i]].getHandObjects()
    for j = #hand, 1, -1 do
      trashcan.putObject(hand[j])
    end
  end
end

-- clean up for play area
function tidyPlayareaCoroutine()
  local trashcan = getObjectFromGUID(TRASHCAN_GUIDS[5])
  local PLAYMATZONE = getObjectFromGUID("a2f932")

  if PLAYMATZONE == nil then
    printToAll("Scripting zone for main play area could not be found!", "Red")
  elseif trashcan == nil then
    printToAll("Trashcan for main play area could not be found!", "Red")
  else
    for _, obj in ipairs(PLAYMATZONE.getObjects()) do
      -- ignore these elements
      if not tableContains(IGNORE_GUIDS, obj.getGUID()) and obj.hasTag(IGNORE_TAG) == false then
        coroutine.yield(0)
        trashcan.putObject(obj)
      end
    end
  end

  printToAll("Tidying playermats and agenda mat...", "White")
  startLuaCoroutine(self, "tidyPlayerMatCoroutine")
  return 1
end

-- clean up for the four playermats and the agenda/act playmat
function tidyPlayerMatCoroutine()
  for i = 1, 5 do
    -- only continue for playermat (1-4) if option enabled
    if options["tidyPlayermats"] or i == 5 then
      -- delay for animation purpose
      for k = 1, 30 do coroutine.yield(0) end

      -- get respective trashcan
      local trashcan = getObjectFromGUID(TRASHCAN_GUIDS[i])
      if trashcan == nil then
        printToAll("Trashcan for " .. COLORS[i] .. " playmat could not be found!", "Red")
        return
      end

      for _, entry in ipairs(findObjects(i)) do
        local obj = entry.hit_object
        local desc_low = string.lower(obj.getDescription())

        -- ignore these elements
        if not tableContains(IGNORE_GUIDS, obj.getGUID()) and obj.hasTag(IGNORE_TAG) == false and
            desc_low ~= "chaos bag" and desc_low ~= "action token" then
          coroutine.yield(0)
          trashcan.putObject(obj)

          -- flip action tokens back to ready
        elseif desc_low == "action token" and obj.is_face_down then
          obj.flip()
        end
      end

      -- reset "activeInvestigatorId"
      if i < 5 then
        local playermat = getObjectFromGUID(PLAYERMAT_GUIDS[i])
        if playermat then
          playermat.setVar("activeInvestigatorId", "00000")
        end
      end
    end
  end

  local datahelper = getObjectFromGUID("708279")
  if datahelper then
    datahelper.setTable("SPAWNED_PLAYER_CARD_GUIDS", {})
  end

  printToAll("Clean up completed!", "Green")
  return 1
end

---------------------------------------------------------
-- helper functions
---------------------------------------------------------

-- find objects depending on index (1 to 4 for playermats, 5 for agenda/act playmat, 6 for campaign log)
function findObjects(num)
  return Physics.cast({
    direction    = { 0, 1, 0 },
    max_distance = 1,
    type         = 3,
    size         = PHYSICS_SCALE[num],
    origin       = PHYSICS_POSITION[num],
    orientation  = { 0, PHYSICS_ROTATION[num], 0 },
    debug        = SHOW_RAYS
  })
end

-- search a table for a value, return true if found (else returns false)
function tableContains(table, value)
  for _, v in ipairs(table) do
    if v == value then
      return true
    end
  end
  return false
end
end)
__bundle_register("core/token/TokenSpawnTrackerApi", function(require, _LOADED, __bundle_register, __bundle_modules)
do
  local TokenSpawnTracker = { }

  local SPAWN_TRACKER_GUID = "e3ffc9"

  TokenSpawnTracker.hasSpawnedTokens = function(cardGuid)
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("hasSpawnedTokens", cardGuid)
  end

  TokenSpawnTracker.markTokensSpawned = function(cardGuid)
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("markTokensSpawned", cardGuid)
  end

  TokenSpawnTracker.resetTokensSpawned = function(cardGuid)
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("resetTokensSpawned", cardGuid)
  end

  TokenSpawnTracker.resetAllAssetAndEvents = function()
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("resetAllAssetAndEvents")
  end

  TokenSpawnTracker.resetAllLocations = function()
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("resetAllLocations")
  end

  TokenSpawnTracker.resetAll = function()
    return getObjectFromGUID(SPAWN_TRACKER_GUID).call("resetAll")
  end

  return TokenSpawnTracker
end
end)
return __bundle_require("__root")