package pl.edu.pw.mini.sg.matrix

import argonaut.{ JsonIdentity, Parse }
import java.io.{File => JFile}
import java.util.UUID
import better.files._
import org.apache.commons.math3.linear.Array2DRowRealMatrix
import org.apache.commons.math3.random.{ CorrelatedRandomVectorGenerator, RandomGenerator, UniformRandomGenerator }
import org.rogach.scallop.ScallopConf
import pl.edu.pw.mini.sg.matrix.MatrixGameConfigJson

final case class Generator(payoffCorrelation: Double, defenderMoves: Int, attackerMoves: Int) {
  def generateGame(implicit rng: RandomGenerator): MatrixGameConfig = {
    val urp = new UniformRandomGenerator(rng)
    val gg = new CorrelatedRandomVectorGenerator(Array(0.0,0.0),
      new Array2DRowRealMatrix(Array(
        Array(1.0,payoffCorrelation),
        Array(payoffCorrelation, 1.0)
      )), 1e-3, urp)

    val payoffs = Vector.fill(defenderMoves, attackerMoves)(
      gg.nextVector() match {case Array(dp, ap) => (
        Math.min(1,Math.max(0, 0.5+(dp/(2*Math.sqrt(3))))),
        Math.min(1,Math.max(0, 0.5+(ap/(2*Math.sqrt(3)))))
      )}
    )
    MatrixGameConfig(UUID.randomUUID(),
      payoffs.map(_.map(_._1)), payoffs.map(_.map(_._2))
    )
  }
}


object Generator {
  def main(args: Array[String]) = {
    val options = new GeneratorOptions(args)
    implicit val rng : RandomGenerator = new org.apache.commons.math3.random.MersenneTwister()
    val generatorConfig = Parse.decode[GeneratorConfig](options.configFile().toScala.contentAsString) match {
      case Right(x) => x
      case Left(err) => throw new Exception(err.toString)
    }
    val generator = Generator(generatorConfig.correlation, generatorConfig.defenderMoves, generatorConfig.attackerMoves)

    Range.inclusive(options.startIndex(), options.endIndex()).foreach(i => {
      val game = generator.generateGame
      val outputFile = File(s"${options.outputPrefix()}-$i.nfgame")
      outputFile.write(JsonIdentity.ToJsonIdentity(game).asJson(MatrixGameConfigJson.matrixGameConfigEncodeJson).toString)
    })
  }




  private[Generator] final class GeneratorOptions(args: Seq[String])
      extends ScallopConf(args){
    val configFile = opt[JFile](name="config", short='c', required=true)
    val outputPrefix = opt[String](name="output-prefix", short='o', required=true)
    val startIndex = opt[Int](name="from-index", short='f', required=true)
    val endIndex = opt[Int](name="to-index", short='t', required=true, descr="inclusive")

    verify()
  }
}


