local CLASSLIB = require("core.class")
local EL = require("camera.EasingLibrary")
local TIMER = require("level.timer")
local CameraSequencerWithStages = CLASSLIB.Class("CameraSequencerWithStages")
local color = require("core.color")
function CameraSequencerWithStages:init(camera)
  self.numMoves = nil
  self.camera = camera
  self.tActions = nil
  self.tDelays = nil
  self.tTimers = nil
  self.tBehaviors = nil
  self.tCameraMoves = nil
  self.tNameOfCameraMoves = nil
  self.numCameraMoves = nil
  self.tPlaylist = nil
  self.numMovesPlayed = nil
  self.bPlayedAllCameraMoves = nil
  self.numCameraMovesCompleted = nil
  self.currStage = 0
  self.numStages = 0
  self.stageLookup = {}
  self.bEndOfCycle = true
  self.bReady = false
end
function CameraSequencerWithStages:SetStage(stagekey)
  self.currStage = stagekey
end
function CameraSequencerWithStages:PrepareEaseTable(movetable, duration)
  local adjustmenttable = {}
  EL.SetupEaseTable(adjustmenttable)
  for attribute, value in pairs(movetable) do
    EL.SetBlendValue(self.camera, adjustmenttable, attribute, value)
  end
  EL.SetDuration(adjustmenttable, duration)
  EL.SetProgress(adjustmenttable, false)
  return adjustmenttable
end
function CameraSequencerWithStages:AddActionToPlaylist(stagename, actionindex)
  local stageName = stagename
  self.numMovesPlayed[stageName] = self.numMovesPlayed[stageName] + 1
  if self.tPlaylist[stageName] == nil then
    self.tPlaylist[stageName] = {}
  end
  if self.tCameraMoves[stageName] ~= nil then
    local move = self.tCameraMoves[stageName][actionindex]
    if move ~= nil then
      EL.SetStartValue(self.camera, move)
      self.tPlaylist[stageName][actionindex] = move
      EL.SetProgress(move, true)
    end
  end
  if self.tBehaviors[stageName] ~= nil then
    local behavior = self.tBehaviors[stageName][actionindex]
    if behavior ~= nil then
      game.FX.SubmitEffect(behavior)
    end
  end
end
function CameraSequencerWithStages:ScanAndPrepareSequence(stagename, camera)
  local stageName = stagename
  local stageActions = self.tActions[stageName]
  for actionindex, _ in pairs(stageActions) do
    local delaytime = self.tDelays[stageName][actionindex]
    if 0 < delaytime then
      self.tTimers[stageName][actionindex] = TIMER.StartLevelTimer(delaytime, function()
        self:AddActionToPlaylist(stageName, actionindex)
      end)
    else
      self:AddActionToPlaylist(stageName, actionindex)
    end
  end
end
function CameraSequencerWithStages:Start(camera)
  if self.numStages > 0 then
    self.currStage = 1
  end
  local stagename = self.stageLookup[self.currStage]
  self:ScanAndPrepareSequence(stagename, camera)
end
function CameraSequencerWithStages:Update(level, camera)
  if self.bEndOfCycle == true then
    return
  end
  local stagename = self.stageLookup[self.currStage]
  assert(stagename, "CameraSequencerWithStages:Update(): Why is the stagename nil?")
  local currPlaylist = self.tPlaylist[stagename]
  local bCompleted
  for _, move in pairs(currPlaylist) do
    if EL.GetProgress(move) == true then
      bCompleted = EL.EaseEverything(level, move, self.camera, "InAndOut", "Quad")
      if bCompleted == true then
        self.numCameraMovesCompleted[stagename] = self.numCameraMovesCompleted[stagename] + 1
        if self.numCameraMovesCompleted[stagename] >= self.numCameraMoves[stagename] then
          self.bPlayedAllCameraMoves[stagename] = true
          self.currStage = self.currStage + 1
          if self.currStage <= self.numStages then
            stagename = self.stageLookup[self.currStage]
            self:ScanAndPrepareSequence(stagename, camera)
          end
          if self.currStage > self.numStages then
            self.bEndOfCycle = true
          end
        end
      end
    end
  end
end
function CameraSequencerWithStages:UpdateWithPrints(level, camera)
  if self.bEndOfCycle == true then
    return
  end
  local stagename = self.stageLookup[self.currStage]
  if self.tPlaylist[stagename] == nil then
    return
  end
  local currPlaylist = self.tPlaylist[stagename]
  local offset, bCompleted
  local numLines = 0
  for moveindex, move in pairs(currPlaylist) do
    if EL.GetProgress(move) == true then
      bCompleted = EL.EaseEverything(level, move, self.camera, "InAndOut", "Quad")
      local debugText = "STAGE[" .. stagename .. "]: Move [" .. self.tNameOfCameraMoves[stagename][moveindex] .. "] has " .. move.duration - move.elapsedTime .. "time left"
      offset = numLines * 12
      engine.DrawText2D(debugText, 600, 600 + offset, color.yellow)
      if bCompleted == true then
        local completedtext = "STAGE[" .. stagename .. "]: Move [" .. moveindex .. "] is COMPLETED"
        numLines = numLines + 1
        offset = numLines * 12
        engine.DrawText2D(completedtext, 600, 600 + offset, color.yellow)
        self.numCameraMovesCompleted[stagename] = self.numCameraMovesCompleted[stagename] + 1
        if self.numCameraMovesCompleted[stagename] >= self.numCameraMoves[stagename] then
          numLines = numLines + 1
          offset = numLines * 12
          engine.DrawText2D("DONE DONE DONE DONE DONE DONE DONE", 600, 600 + offset, color.red)
          self.bPlayedAllCameraMoves[stagename] = true
          self.currStage = self.currStage + 1
          if self.currStage <= self.numStages then
            stagename = self.stageLookup[self.currStage]
            self:ScanAndPrepareSequence(stagename, camera)
          else
            self.bEndOfCycle = true
          end
        end
      end
      numLines = numLines + 1
    end
  end
end
function CameraSequencerWithStages:InitTable(thistable, stagename, value)
  if thistable == nil then
    thistable = {}
  end
  if thistable[stagename] == nil then
    if value == nil then
      thistable[stagename] = {}
    else
      thistable[stagename] = value
    end
    return thistable
  else
    assert(nil, "InitTable(): This table was already created with the stagename: " .. stagename)
  end
end
function CameraSequencerWithStages:CreateStage(stagename)
  local stageName = stagename
  local stageCheck = self:GetStageIndex(stageName)
  assert(stageCheck == nil, "CreateStage(): This stage was already created with the stagename: " .. stagename)
  self.numStages = self.numStages + 1
  self.bEndOfCycle = false
  self.stageLookup[self.numStages] = stageName
  self.tActions = self:InitTable(self.tActions, stageName)
  self.numMoves = self:InitTable(self.numMoves, stageName, 0)
  self.tDelays = self:InitTable(self.tDelays, stageName)
  self.tTimers = self:InitTable(self.tTimers, stageName)
  self.tBehaviors = self:InitTable(self.tBehaviors, stageName)
  self.tCameraMoves = self:InitTable(self.tCameraMoves, stageName)
  self.tNameOfCameraMoves = self:InitTable(self.tNameOfCameraMoves, stageName)
  self.numCameraMoves = self:InitTable(self.numCameraMoves, stageName, 0)
  self.tPlaylist = self:InitTable(self.tPlaylist, stageName)
  self.numMovesPlayed = self:InitTable(self.numMovesPlayed, stageName, 0)
  self.bPlayedAllCameraMoves = self:InitTable(self.bPlayedAllCameraMoves, stageName, false)
  self.numCameraMovesCompleted = self:InitTable(self.numCameraMovesCompleted, stageName, 0)
end
function CameraSequencerWithStages:GetStageIndex(stagename)
  for index, name in pairs(self.stageLookup) do
    if name == stagename then
      return index
    end
  end
  return nil
end
function CameraSequencerWithStages:AddToStage(stagename, action, duration, delay, actionname, behaviortable)
  assert(action, "::AddToStage() failed. Action does not exist")
  local stageName = stagename
  assert(self:GetStageIndex(stageName), "You need to allow stages to be used. Call function CreateStage() first!")
  self.numMoves[stageName] = self.numMoves[stageName] + 1
  local moveIndex = self.numMoves[stageName]
  local cameraadjustment = action.Adjustment
  local camerabehavior = action.Effect
  self.tActions[stageName][moveIndex] = action
  self.tDelays[stageName][moveIndex] = delay
  if cameraadjustment ~= nil then
    self.numCameraMoves[stageName] = self.numCameraMoves[stageName] + 1
    self.tCameraMoves[stageName][moveIndex] = self:PrepareEaseTable(cameraadjustment, duration)
    self.tNameOfCameraMoves[stageName][moveIndex] = actionname
  end
  if camerabehavior ~= nil then
    self.tBehaviors[stageName][moveIndex] = camerabehavior
  end
end
function CameraSequencerWithStages:SwitchToStage(stagename, camera)
  self.currStage = stagename
  self:ScanAndPrepareSequence(self.currStage, camera)
  self.bPlayedAllCameraMoves[stagename] = false
  self.numCameraMovesCompleted[stagename] = 0
end
function CameraSequencerWithStages:GetNameOfAttributeInMoveTable(table)
  for k, v in pairs(table) do
    if EL.IsValidCameraAttribute(k) and v.name ~= nil then
      return v.name
    end
  end
  return nil
end
return {CameraSequencerWithStages = CameraSequencerWithStages}
