package pl.edu.pw.mini.sg.movingtargets

import com.google.common.collect.ImmutableList
import pl.edu.pw.mini.jk.sg.game.common.State
import pl.edu.pw.mini.jk.sg.game.immutable.Payoffs

case class MovingTargetsImmutableGame(
  attackStarted: Option[AttackStart],
  gameConfig: MovingTargetsGameConfig,
  defenderPositions: MovingTargetsDefenderState,
  attackerState: MovingTargetsAttackerState,
  defenderScore: Double,
  attackerScore: Double
) extends State[MovingTargetsAttackerState, MovingTargetsDefenderState] {

  private implicit val gC = gameConfig

  final def timeStep = defenderPositions.timeStep

  def makeMoves(defenderMove: MovingTargetsDefenderMove, attackerMove: AttackerDecision) : (Payoffs, MovingTargetsImmutableGame)  = {
    val newDefenderState = defenderPositions.advance(defenderMove)
    val newAttackerState = attackerState.advance(attackerMove)
    val newAttackStarted = attackerMove match {
      case WaitDecision => attackStarted
      case AttackDecision(target) => Some(AttackStart(defenderPositions.timeStep+1, target))
    }
    val p = gameConfig.getRewardForAS(newAttackStarted, newDefenderState.currentPositions, defenderPositions.timeStep + 1)

    (p._1, copy(attackStarted = p._2,
      defenderPositions = newDefenderState, attackerState = newAttackerState,
      defenderScore = defenderScore+p._1.defenderPayoff, attackerScore = attackerScore+p._1.attackerPayoff))
  }

  override def getAttackerVisibleState: MovingTargetsAttackerState = attackerState
  override def getDefenderVisibleState: MovingTargetsDefenderState = defenderPositions
}


object MovingTargetsImmutableGame {
  def toImmutableList[T](list: List[T]) : ImmutableList[T] = {
    val builder = ImmutableList.builder[T]
    list.foreach(builder.add(_))
    builder.build()
  }

  def fromConfig(config: MovingTargetsGameConfig) = MovingTargetsImmutableGame(None, config,
    MovingTargetsDefenderState(config.defenderStartingPositions, 0, config),
    MovingTargetsAttackerState(0, false, toImmutableList(WaitDecision :: config.targets.map(t => AttackDecision(t.id)).toList)), 0, 0)
}
