package pl.edu.pw.mini.sg.game.deterministic;

import argonaut.{EncodeJson, Json}
import pl.edu.pw.mini.sg.rng.RandomGenerator

import scala.annotation.tailrec




trait BehavioralStrategy[M, S] {
  def probabilities: Seq[(M, Double)]
  def randomMove(rng: RandomGenerator) : M = {
    val rand = rng.nextDouble()

    @tailrec
    def choose(level: Double, list: Seq[(M, Double)]) : M = {
      if(list.head._2 >= level)
        list.head._1
      else
        choose(level-list.head._2, list.tail)
    }

    choose(rand, probabilities)
  }

  def nextState(move: M, reachedState: S) : BehavioralStrategy[M, S]

  def successorsInTree : Iterable[(M, S)]
  def state : S
}

object BehavioralStrategy {
  val STATE_KEY = "state"
  val PROBABILITIES_KEY = "probabilities"
  val SUCCESSORS_KEY = "successors"


  implicit def strategyEncode[DM, DS](implicit dmCodec: EncodeJson[DM], dsCodec: EncodeJson[DS]) : EncodeJson[BehavioralStrategy[DM, DS]] = {
    def enc(msn: BehavioralStrategy[DM, DS]) : Json = {
      import argonaut.Argonaut._

      implicit val ej = EncodeJson[BehavioralStrategy[DM, DS]](enc)
      (STATE_KEY := msn.state) ->: (PROBABILITIES_KEY :=  msn.probabilities.toList) ->: (SUCCESSORS_KEY := msn.successorsInTree.map{case (m, s) => (m, msn.nextState(m,s))}.toList) ->: jEmptyObject
    }
    EncodeJson(enc)
  }
}
