package pl.edu.pw.mini.sg.se
import argonaut.{CursorHistory, Json}
import pl.edu.pw.mini.sg.bosansky._
import pl.edu.pw.mini.sg.game.Payoff
import pl.edu.pw.mini.sg.game.boundedrationality.DistortedPayoff
import pl.edu.pw.mini.sg.game.deterministic.plugin.GameParams
import pl.edu.pw.mini.sg.game.deterministic.{AdvanceablePlayerVisibleState, DeterministicGame, PlayerVisibleState}
import pl.edu.pw.mini.sg.mixed.tree.MixedStrategyNode
import pl.edu.pw.mini.sg.results.MethodInfo
import pl.edu.pw.mini.sg.rng.RandomGenerator
import scalaz.{NonEmptyList, Validation}
import squants.Time
import squants.time.Seconds

class BosanskyMethod(config: BosanskyConfig) extends StrategyMethod {
  private val solver = config.solverConfig.solverFromConfig

  override def findBehavioralStrategy[DM, AM, DS <: PlayerVisibleState[DM], AS <: AdvanceablePlayerVisibleState[AM, AS], G <: DeterministicGame[DM, AM, DS, AS, G]]
  (game: G, params: GameParams, rng: RandomGenerator): (MixedStrategyNode[DM, DS, Unit], DistortedPayoff, Time) = {
    val utils = new DeterministicGameUtilsProvider[DM, AM, DS, AS, G]
    val gameSolver = new DeterministicGameSolver(solver, utils)
    val (msn, payoff, time) = gameSolver.findStrategy(game, config.M, config.timeLimitSeconds.map(Seconds.apply[Double]), config.payoffChanger, config.anchoringAlpha)
    (msn, new DistortedPayoff(new Payoff(payoff.defender, payoff.attacker), new Payoff(Double.NaN, payoff.attacker)), time)
  }

  override def getMethodInfo(configFileName: String, gitHash: String, version: String): MethodInfo = {
    BosanskyMethodInfo(configFileName, gitHash, version, solver.solverInfo)
  }
}

object BosanskyMethodParser extends StrategyMethodParser[BosanskyMethod] {
  override def tryParse(config: Json): Validation[NonEmptyList[(String, CursorHistory)], BosanskyMethod] = {
    Validation.fromEither(config.as(BosanskyConfigJson.bosanskyConfigCodec).toEither).map(new BosanskyMethod(_)).toValidationNel
  }

  override val name = "BC2015"
}

