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

import com.google.common.collect.ImmutableList
import org.apache.commons.math3.random.RandomGenerator
import pl.edu.pw.mini.jk.sg.game.common.advanceable.AdvanceableDefenderState

import collection.JavaConverters._
import scala.runtime.ScalaRunTime

case class MovingTargetsDefenderState (
  currentPositions: Vector[DefenderPosition],
  timeStep: Int,
  gameConfig: MovingTargetsGameConfig
) extends AdvanceableDefenderState[MovingTargetsDefenderMove] {
  private implicit val gC = gameConfig

  override lazy val hashCode = ScalaRunTime._hashCode(this)
  val EPS = 1e-6

  override def advance(move: MovingTargetsDefenderMove) : MovingTargetsDefenderState = if(verifyMove(move))
    copy(currentPositions = move.newPositions, timeStep = timeStep+1)
  else
    throw new IllegalStateException("Move not allowed in state")
  override def getPossibleMoves(): ImmutableList[MovingTargetsDefenderMove] =  possibleMovesIl
  override def getTimeStep(): Int = timeStep

  private def verifyMove(move : MovingTargetsDefenderMove) : Boolean =
    move.newPositions.length == currentPositions.length &&
  move.newPositions.zip(currentPositions).forall{case (a,b) =>  GeometryHelpers.distanceSq(a.asPositionTuple, b.asPositionTuple) <= gameConfig.defenderMoveRangeSquared + EPS}


  override def getRandomMove(rng: RandomGenerator) : MovingTargetsDefenderMove = MovingTargetsDefenderMove(currentPositions.map(gameConfig.randomPossiblePosition(_, rng)))

  private def possibleUnitMoves : Seq[Seq[DefenderPosition]] =
    currentPositions.map(gameConfig.possiblePositions)

  final def possibleMoves : Stream[MovingTargetsDefenderMove] =
    possibleUnitMoves.foldLeft(Stream(Vector[DefenderPosition]()))(
      (mv, d) => mv.flatMap(m => d.map(m :+ _))
    ).map(MovingTargetsDefenderMove.apply)

  private lazy val possibleMovesIl = ImmutableList.copyOf(asJavaIterableConverter(possibleMoves).asJava)
}
