package pl.edu.pw.mini.jk.sg.game.configuration;

import scala.collection.JavaConverters._
import scala.reflect.ClassTag

import argonaut.{CodecJson, DecodeJson, EncodeJson}
import pl.edu.pw.mini.jk.lib.JsonHelpers
import pl.edu.pw.mini.jk.sg.game.graph.advanceable.AdvanceableGraphGameConfiguration

class DecodeAdvanceableGraphGameConfiguraionJson

object DecodeAdvanceableGraphGameConfiguraionJson {
  implicit val codecEdge : CodecJson[Edge] = CodecJson.codec2[Int, Int, Edge](new Edge(_,_),
    (e: Edge) => (e.from, e.to))("from", "to")

  implicit val codecGraphDescription : CodecJson[GraphDescription] =
    CodecJson.casecodec2(
      GraphDescription.apply,
      GraphDescription.unapply)("vertexCount", "edges")


  implicit val codecDefenseProbabilityFunc : CodecJson[DefenseProbabilityFunction] =
    JsonHelpers.enumerationCodec(List (
      ("DISCRETE", DiscreteProbabilityFunction)
    ))

  def createSGC(graph: GraphDescription, targets: List[Integer], spawns: List[Integer],
    defenderPenalties: Array[Array[Int]], attackerRewards: Array[Array[Int]],
    vertexDefenderRewards: Array[Array[Int]], vertexAttackerPenalties: Array[Array[Int]],
    attackerCount: Int, defenderCount: Int, defenseProbabilityFunc: DefenseProbabilityFunction,
    stateHistoryHorizon: Int, historyTimeHorizon: Int) : StaticGameConfiguration =
    new StaticGameConfiguration(graph, targets.asJava, spawns.asJava, defenderPenalties, attackerRewards, vertexDefenderRewards, vertexAttackerPenalties, attackerCount, defenderCount, defenseProbabilityFunc, stateHistoryHorizon, historyTimeHorizon)

  implicit def ArrayDecodeJson[T](implicit da: DecodeJson[T], ct: ClassTag[T]) : DecodeJson[Array[T]] = DecodeJson.ListDecodeJson[T](da).map(_.toArray)

  implicit def ArrayEncodeJson[T](implicit ea: EncodeJson[T]) : EncodeJson[Array[T]] = EncodeJson.ListEncodeJson[T].contramap[Array[T]](_.toList)

  implicit val codecStaticGameConfiguration : CodecJson[StaticGameConfiguration] =
    CodecJson.codec12(
      createSGC, (sgc: StaticGameConfiguration) => (sgc.getGraphDescription,
        sgc.getTargets.asScala.toList, sgc.getSpawns.asScala.toList,
        sgc.getDefenderPenalties, sgc.getAttackerRewards, sgc.getVertexDefenderRewards,
        sgc.getVertexAttackerPenalties, sgc.getAttackerCount, sgc.getDefenderCount,
        sgc.getDefenseProbabilityFunc, sgc.getStateHistoryHorizon, sgc.getHistoryTimeHorizon)
    )("graph", "targets", "spawns", "defenderPenalties", "attackerRewards", "vertexDefenderRewards",
      "vertexAttackerPenalties", "attackerCount", "defenderCount", "defenseProbabilityFunc",
      "stateHistoryHorizon", "historyTimeHorizon")
    
  implicit val codecAdvanceableGraphGameConfiguration : CodecJson[AdvanceableGraphGameConfiguration] =
    CodecJson.codec2(
      (sgc: StaticGameConfiguration, aC: Int) => new AdvanceableGraphGameConfiguration(sgc,aC),
      (aggc: AdvanceableGraphGameConfiguration) => (aggc.getStaticGameConfiguration, aggc.getNumberOfAttackers)
    )("staticGameConfiguration", "attackerCount")

  def readAggc(json: String) : AdvanceableGraphGameConfiguration =
    JsonHelpers.readWithException[AdvanceableGraphGameConfiguration](json)

  def readSgc(json: String) : StaticGameConfiguration =
    JsonHelpers.readWithException[StaticGameConfiguration](json)

  def encodeAggc(aggc: AdvanceableGraphGameConfiguration) : String =
    codecAdvanceableGraphGameConfiguration.apply(aggc).toString
}
