package pl.edu.pw.mini.jk.sg.mixeduct

import com.google.common.collect.ImmutableList
import org.apache.commons.collections4.Factory
import org.apache.commons.math3.random.RandomGenerator
import pl.edu.pw.mini.jk.sg.game.{DefenderAttackerGame, NormalizableFactory}
import pl.edu.pw.mini.jk.sg.game.common.{DefenderMove, SecurityGame}
import pl.edu.pw.mini.jk.sg.game.common.advanceable.AdvanceableState
import pl.edu.pw.mini.jk.sg.mixeduct.attacker.AttackerStrategy
import pl.edu.pw.mini.jk.sg.uct.{PayoffInfo, SinglePlayerGame}

final class DefenderSecurityGameView[M <: DefenderMove, AM, S <: AdvanceableState[M], G <: SecurityGame with DefenderAttackerGame[AM, M, _, _ <: S, _]](
  game: G, attackerStrategy: ImmutableList[AM]
) extends SecurityGame with SinglePlayerGame[M, S] {
  var moveNumber = 0

  override def getCurrentState() = game.getDefenderState
  override def possibleMoves() = game.getDefenderState.getPossibleMoves
  override def makeMove(move: M) = {
    game.playAttackerMove(attackerStrategy.get(moveNumber))
    game.playDefenderMove(move)
    val pi = game.finishRound()
    moveNumber += 1
    PayoffInfo(pi.defenderPayoff, pi.catchAccidentsCount, pi.attackAccidentsCount)
  }
  override def randomMove(rng: RandomGenerator) = game.randomDefenderMove(rng)
  override def getTimeStep() = game.getTimeStep
  override def getPreviousAccidents() = game.getPreviousAccidents
  override def accidentOccured() = game.accidentOccured()
}

object DefenderSecurityGameView {
  def transformFactory[M <: DefenderMove, AM, S <: AdvanceableState[M], G <: SecurityGame with DefenderAttackerGame[AM, M, _, _ <: S, _]](
    factory: NormalizableFactory[AM, M, G],
    attackerStrategy: AttackerStrategy[AM]
  ): Factory[DefenderSecurityGameView[M, AM, S, G]] = {
    new Factory[DefenderSecurityGameView[M, AM, S, G]] {
      override def create = new DefenderSecurityGameView(factory.create, attackerStrategy.sample())
    }
  }
}
