package pl.edu.pw.mini.sg.compactlp

import pl.edu.pw.mini.sg.compactlp.model._
import pl.edu.pw.mini.sg.compactlp.util.{Attacker, Position}
import pl.edu.pw.mini.sg.movingtargets.{AttackerDecision, DefenderPosition}

/**
  * Trait dla wrappera wokol klasy gry. Zawiera wszystkie metody, ktorych [[CompactLPSolver]] potrzebuje wyznaczenia
  * rozwiazania
  */
trait CompactGameWrapper {
  /**
    * Zwraca wszystkie strategie atakujacego wraz z wyplatami.
    *
    * @return Sekwencja strategii
    */
  def getAttackerStrategiesWithPayoffs: Seq[AttackerWithPayoffs]

  /**
    * Oblicza faktyczne wyplaty dla danej strategii atakujacego i obroncow
    *
    * @param attackerStrategy  Strategia atakujacego, zawiera informacje o tym jaki cel jest atakowany i w jakim czasie.
    *                          Moze byc ewentualnie puste (None), wtedy jest to interpretowane jako brak ataku
    * @param defenderPositions Lista o dlugosci rownej dlugosci gry, gdzie kazdy element to pozycje wszystkich obroncow
    *                          w danym czasie
    * @return (wyplata obroncy, wyplata atakujacego)
    */
  def getPayoffs(attackerStrategy: Option[Attacker], defenderPositions: List[Seq[Position]]): (Double, Double)

  /**
    * Zwraca dyskretna siatke gry
    *
    * @param sparsity Wspolczynnik agregacji s
    * @return Sekwencja elementow siatki
    */
  def getZones(sparsity: Int): Seq[GridPosition]

  /**
    * Zamienia pozycje w dyskretnej siatce gry na prawdziwa pozycje w grze
    *
    * @param position Pozycja w dyskretnej siatce
    * @return Prawdziwa pozycja w grze, juz na liczbach zmiennoprzecinkowych
    */
  def gridToRealPosition(position: GridPosition): Position

  /**
    * Zwraca dlugosc gry (liczbe krokow czasowych)
    *
    * @param sparsity Wspolczynnik agregacji s
    * @return Liczba krokow czasowych
    */
  def getTimeSteps(sparsity: Int): Int

  /**
    * Zwraca liczbe obroncow w grze
    *
    * @return Liczba obroncow
    */
  def getDefenderCount: Int

  /**
    * Zwraca pozycje startowe wszystkich obroncow z dyskretnej siatce. Moze zawierac duplikaty, jak wiele obroncow
    * startuje w tym samym miejscu
    *
    * @param sparsity Wspolczynnik agregacji s
    * @return Sekwencja o dlugosci rownej liczbie obroncow z elementami siatki
    */
  def getDefenderStartingPositions(sparsity: Int): Seq[GridPosition]

  /**
    * Dlugosc ataku. Atak rozpoczynajacy sie w czasie t trwa do czasu t + dlugosc wlacznie. Dlugosc == 0 oznacza, ze
    * atak konczy sie w tym kroku czasowym, co sie rozpoczyna
    *
    * @return Dlugosc ataku (liczba krokow czasowych)
    */
  def getAttackLength: Int

  /**
    * Dla danego atakujacego zwraca wszystkie pozycje dla wszystkich krokow czasowych, na ktorych obronca musi byc,
    * aby zlapac atakujacego. Uzywane tylko dla sparsity = 1
    *
    * @param attacker Strategia atakujacego
    * @return Sekwencja pozycji wraz z czasem
    */
  def getNeighbours(attacker: Attacker): Seq[GridSpacetime]

  /**
    * Zwraca wspolczynnik pokrycia ataku przy przejsciu obroncy miedzy dwoma pozycjami w siatce zagregowanej.
    * Mozna to uznac za prawdopodobienstwo zlapania atakujacego podczas danego przejscia, ktore w rzeczywistosci
    * sklada sie z wiekszej ilosci krokow (w oryginalnej siatce) oraz jest rozproszone na caly zagregowany kwadrat.
    * Metoda oblicza wszystkie pozycje posrednie obroncy juz dla rozproszonej sciezki i liczy ile pozycji pokrywa sie z
    * z pozycjami atakujacego podczas ataku. Na koniec ta liczba jest dzielona przez sparsity * sparsity, poniewaz
    * tyle razy sciezka zostala powielona i zakladamy, ze kazda rozproszona sciezka jest wybierana z rownym
    * prawdopodobienstwem
    *
    * @param flow     Przeplyw miedzy pozycjami i w czasie dla ktorych liczymy coverage
    * @param attackerNeighbours Pozycje ktore lapia atakujacego
    * @param sparsity Wspolczynnik agregacji s
    * @return Double z przedzialu [0, 1] oznaczajacy prawdopodobienstwo zlapania
    */
  def getCoverage(flow: Flow, attackerNeighbours: Seq[GridSpacetime], sparsity: Int): Double

  /**
    * Dla podanej pozycji w dyskretnej siatce zwraca wszystkie pozycje osiagalne przez obronce
    *
    * @param position Aktualna pozycja w siatce, dla ktorej wyznaczane sa te osiagalne
    * @param sparsity Wspolczynnik agregacji s
    * @return Sekwencja pozycji w dyskretnej siatce osiagalne przez obronce
    */
  def getGridNeighbours(position: GridPosition, sparsity: Int): Seq[GridPosition]
}
