package pl.edu.pw.mini.sg.se

import argonaut.{CursorHistory, Json}
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.rng.RandomGenerator
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 scalaz.{NonEmptyList, Validation}
import scalaz._
import scalaz.syntax._
import scalaz.syntax.semigroup._
import scalaz.syntax.traverse1._
import squants.time.Time

trait StrategyMethod {
  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)

  def getMethodInfo(configFileName: String, gitHash: String, version: String): MethodInfo
}

trait StrategyMethodParser[+X <: StrategyMethod] {
  def tryParse(config: Json) : Validation[NonEmptyList[(String, CursorHistory)], X]
  def name: String
}

object StrategyMethodParser {

  def tryParse[X <: StrategyMethod](parsers: NonEmptyList[StrategyMethodParser[X]])(config: Json)
      : Validation[NonEmptyList[(String,NonEmptyList[(String, CursorHistory)])], X] = {
    implicit def sg[A,B](implicit sa: Semigroup[A]) = new Semigroup[Validation[A,B]] {
      def append(v1 : Validation[A,B],
        v2: => Validation[A,B]) = v1.findSuccess(v2)
 }

    parsers.foldMap1(x => (x.tryParse(config)
      .leftMap((nel: NonEmptyList[(String, CursorHistory)])  => NonEmptyList((x.name, nel)))))


  }
}

