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

import argonaut.Json
import java.io.File

import scala.io.Source

import argonaut.{DecodeJson, Parse}
import org.apache.commons.math3.random.RandomGenerator
import pl.edu.pw.mini.jk.lib.{JsonHelpers, TraitJsonDecoder}
import pl.edu.pw.mini.jk.sg.game.common.{Cloneable, DefenderMove, SecurityGame}
import pl.edu.pw.mini.jk.sg.game.common.advanceable.{AdvanceableAttackerState, AdvanceableDefenderState}
import pl.edu.pw.mini.jk.sg.mixeduct.{MixedUctConfig, MixedUctConfigDecodeJson}
import result.TimedTrainingResultFactory
import pl.edu.pw.mini.jk.sg.game.{DefenderAttackerGame, GameVariant => GameVariant2}
import pl.edu.pw.mini.jk.sg.mixeduct.{TreeLogConfig, TreeLogConfigDisable}

object MilpConfig extends MethodConfig {
  override val name = "MILP"
//  override val gameVariant = GameVariant2.SingleMovePerTimestep
}

case class RandomConfig(gameVariant: GameVariant2) extends GameVariantMethodConfig {
  override def getGameVariant = gameVariant
  override def name = "Uniform"


   override def performTrainingWithGame[DM <: DefenderMove, AM, AS <: AdvanceableAttackerState[AM], DS <: AdvanceableDefenderState[DM], G <: Cloneable[G] with SecurityGame with DefenderAttackerGame[AM, DM, AS, DS, _]](gameMatrices: GameMatrices[AM, DM, AS, DS, G],
       rng : RandomGenerator) : TimedTrainingResultFactory[DM,AM] = UniformPlayer.uniformPlayer(gameMatrices)
}

class MethodConfigDecoder

object MethodConfigDecoder {
  implicit val decodeGameVariant : DecodeJson[GameVariant2] = JsonHelpers.readOneFromSet(x => x match {
    case "SINGLE_MOVE_PER_TIMESTEP"  => GameVariant2.SingleMovePerTimestep
    case "MULTI_MOVE_PER_TIMESTEP" => GameVariant2.MultiMovePerTimestep
    case "COORD_MOVE" => GameVariant2.CoordMove
    case "COMPACT_GAME" => GameVariant2.CompactGame
  })
  val milpDecoder: DecodeJson[MethodConfig] = DecodeJson.UnitDecodeJson.map(x => MilpConfig)
  val randomDecoder: DecodeJson[RandomConfig] = DecodeJson.jdecode1L(RandomConfig.apply)("gameVariant")
  val mixedUctDecoder: DecodeJson[MixedUctConfig] = MixedUctConfigDecodeJson.defaultDecoder

  def randomConfigInstance = RandomConfig
  def milpConfigInstance = MilpConfig

  def decoder(tlc: TreeLogConfig): DecodeJson[MethodConfig] = TraitJsonDecoder[MethodConfig](Map("milp" -> milpDecoder,
    "mixedUct" -> mixedUctDecoder.map(_.copy(treeLogConfig=tlc)), "random" -> randomDecoder)).decoder


  def fromFile(file: File) : (MethodConfig, Json) = Parse.parse(Source.fromFile(file).mkString).right.flatMap(json => json.as(decoder(TreeLogConfigDisable)).toEither.right.map((_, json))) match {
    case Left(x) => throw new RuntimeException("Parse exteption: " + x)
    case Right(v) => v
  }

  def fromFile(file: File, treeLogConfig: TreeLogConfig) : (MethodConfig, Json) = Parse.parse(Source.fromFile(file).mkString).right.flatMap(json => json.as(decoder(treeLogConfig)).toEither.right.map((_, json))) match {
    case Left(x) => throw new RuntimeException("Parse exteption: " + x)
    case Right(v) => v
  }
}
