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

import java.util.UUID
import pl.edu.pw.mini.sg.game.deterministic.plugin.config.GameConfig


// Outer dimension -- defender
// Innner -- attacker 
final case class MatrixGameConfig(
  id: UUID,
  defenderMatrix: Vector[Vector[Double]],
  attackerMatrix: Vector[Vector[Double]]) extends GameConfig {
  {
    val c = MatrixGameConfig.verifyMarices(defenderMatrix, attackerMatrix)
    require(c == Right(()), c)
  }

  @inline
  def defenderMoveCount : Int = defenderMatrix.size
  @inline
  def attackerMoveCount : Int = defenderMatrix(0).size
  @inline
  def getDefenderPayoff(defenderMove: Int, attackerMove: Int) = defenderMatrix(defenderMove)(attackerMove)
  @inline
  def getAttackerPayoff(defenderMove: Int, attackerMove: Int) = attackerMatrix(defenderMove)(attackerMove)
}

object MatrixGameConfig {
  def getSecondDimension(v: Vector[Vector[_]]): Either[String, Int] = {
    if (v.length == 0)
      Left("First dimension is 0!")
    else if (v.forall(_.length == v(0).length))
      Right(v(0).length)
    else
      Left(s"Second dimension vectors do not match: ${v.view.map(_.length)}")
  }

  def getMatrixDimensions(v: Vector[Vector[_]]) : Either[String, (Int, Int)] = {
    getSecondDimension(v).right.flatMap(d => if(d > 0) Right((v.length, d)) else Left(s"Inner matrix dimension is 0"))
  }

  def verifyMarices(dm: Vector[Vector[_]], am: Vector[Vector[_]]) : Either[String, Unit] = {
    for {
      dimd <- getMatrixDimensions(dm)
      dima <- getMatrixDimensions(am)
    } yield ( (dima, dimd) match {
      case ((wa,ha),(wd,hd)) =>
        if(wa==wd && ha == hd) Right(Unit)
        else Left(s"Attacker and defender matrix dimensions do not match, def: ${wd}×${hd}, att: ${wa}×${ha}")
    })
  }
}
