package pl.edu.pw.mini.sg.mixed.adjuster

import pl.edu.pw.mini.sg.rng.RandomGenerator
import pl.edu.pw.mini.sg.game.deterministic.PlayerVisibleState
import pl.edu.pw.mini.sg.mixed.IterationInfo
import pl.edu.pw.mini.sg.mixed.tree.{ InnerResultNode, MixedStrategyNode }


trait AssesmentBasedAdjuster extends StatefulAdjuster {

  def ISRLU(alpha: Double)(x: Double) : Double =
    if(x<0)
      x/Math.sqrt(1+alpha*x*x)
    else
      x

  def negISRLU(alpha: Double)(x: Double) : Double =
    - ISRLU(alpha)(-x)

  def updateState(
    oldState: AdjusterState,
    assesments: Seq[Double]
  )(implicit
    rng: RandomGenerator
  ): AdjusterState


  def updateStrategy(
    mixedStrategyNode: MixedStrategyNode[_,_, _],
    adjusterState: AdjusterState,
    assesments: Seq[Double]
  )(implicit
    rng: RandomGenerator,
    iterationInfo: IterationInfo
  ) : Boolean

    /**
    *  @return Czy była zmiana
    */
  def inTreeAdjust[DM, DS <: PlayerVisibleState[DM]](
    mixedStrategy: MixedStrategyNode[DM, DS, AdjusterState],
    desiredAttackerPayoff: InnerResultNode[DM, DS],
    optimalAttackerPayoff: InnerResultNode[DM, DS]
  )(
    implicit rng: RandomGenerator,
    iterationInfo: IterationInfo
  ) : Boolean = {
    val diff = desiredAttackerPayoff.payoff.distortedAttacker.attacker - optimalAttackerPayoff.payoff.distortedAttacker.attacker
    def diffm(move: DM) = desiredAttackerPayoff.payoff(move).distortedAttacker.attacker - optimalAttackerPayoff.payoff(move).distortedAttacker.attacker
    val assesments = mixedStrategy.probabilities.view.map(p => diffm(p._1) - diff).toVector
    mixedStrategy.optimizerState = updateState(mixedStrategy.optimizerState, assesments)
    updateStrategy(mixedStrategy, mixedStrategy.optimizerState, assesments)
  }

   /**
    *  @return Czy była zmiana
    */
  def outOfTreeAdjust[DM, DS <: PlayerVisibleState[DM]](
    mixedStrategy: MixedStrategyNode[DM, DS, AdjusterState],
    optimalAttackerPayoff: InnerResultNode[DM, DS]
  )(
    implicit rng: RandomGenerator,
    iterationInfo: IterationInfo
 ) : Boolean = {
    val assesments = mixedStrategy.probabilities.view.map(p =>
       optimalAttackerPayoff.payoff.distortedAttacker.attacker - optimalAttackerPayoff.payoff(p._1).distortedAttacker.attacker).toVector
   mixedStrategy.optimizerState = updateState(mixedStrategy.optimizerState, assesments)
   updateStrategy(mixedStrategy, mixedStrategy.optimizerState, assesments)
 }


   /**
    *  @return Czy była zmiana
    */
 def positiveAdjust[DM, DS <: PlayerVisibleState[DM]](
    mixedStrategy: MixedStrategyNode[DM, DS, AdjusterState],
    gamePayoff: InnerResultNode[DM, DS]
  )(
   implicit rng: RandomGenerator,
    iterationInfo: IterationInfo
 ) : Boolean = {
   val assesments = mixedStrategy.probabilities.view.map(p =>
       gamePayoff.payoff(p._1).real.defender - gamePayoff.payoff.real.defender).map(_*3).toVector
   mixedStrategy.optimizerState = updateState(mixedStrategy.optimizerState, assesments)
   updateStrategy(mixedStrategy, mixedStrategy.optimizerState, assesments)
 }

}
