package pl.edu.pw.mini.sg.mcts.json

import argonaut.{ CodecJson, DecodeJson, EncodeJson }
import pl.edu.pw.mini.sg.json.{ FlatTraitJsonCodec, TraitSubtypeCodec }
import pl.edu.pw.mini.sg.mcts.propagation.SimplePropagation
import pl.edu.pw.mini.sg.mcts.selection.UctSelection
import pl.edu.pw.mini.sg.mcts.tree.simple.SimpleTreeFactory
import pl.edu.pw.mini.sg.mcts.tree.stat.{StatCalculator, MeanStatCalculator, MaxStatCalculator}
import pl.edu.pw.mini.sg.mcts.{ MctsParameters, UniformRandomMove }
import pl.edu.pw.mini.sg.mcts.selection.MctsSelection


object MctsParametersJson {
  implicit val uctSelectionCodec: CodecJson[UctSelection] = CodecJson.casecodec1(
    UctSelection.apply, UctSelection.unapply)("c")

  implicit val selectionFunctionsCodec : FlatTraitJsonCodec[MctsSelection] =
    new FlatTraitJsonCodec[MctsSelection](List(
      new TraitSubtypeCodec(uctSelectionCodec, uctSelectionCodec, "uct")
    ))

  implicit val statCalculatorCodec : FlatTraitJsonCodec[StatCalculator] =
    new FlatTraitJsonCodec[StatCalculator](List(
      TraitSubtypeCodec.singletonCodec(MeanStatCalculator, "mean"),
      TraitSubtypeCodec.singletonCodec(MaxStatCalculator, "max")
    ))


  val SELECTION_FIELD = "selection"
  val SIMULATIONS_FIELD = "simulations"
  val STAT_CALC_FIELD = "statCalc"

  implicit def mctsParametersDecode(implicit mctsSelectionD: DecodeJson[MctsSelection], statCalculatorD: DecodeJson[StatCalculator]) : DecodeJson[MctsParameters] =
    DecodeJson.jdecode3L((sel: MctsSelection, simulations: Int, calc: StatCalculator) =>
      MctsParameters(simulations, sel, UniformRandomMove, SimplePropagation, SimpleTreeFactory(calc))
    )(SELECTION_FIELD, SIMULATIONS_FIELD, STAT_CALC_FIELD)(mctsSelectionD, DecodeJson.IntDecodeJson, statCalculatorD)

  implicit def mctsParametersEncode(implicit mctsSelectionE: EncodeJson[MctsSelection], statCalculatorE: EncodeJson[StatCalculator]) : EncodeJson[MctsParameters] =
    EncodeJson.jencode3L((mp: MctsParameters) => (mp.mctsSelection, mp.simulationsInRoot, mp.treeFactory.statCalculator)
    )(SELECTION_FIELD, SIMULATIONS_FIELD, STAT_CALC_FIELD)(mctsSelectionE, EncodeJson.IntEncodeJson, statCalculatorE)
}
