package pl.edu.pw.mini.jk.sg.uct.statsupdater.fixedlength

import org.scalamock.scalatest.MockFactory
import org.scalatest._
import pl.edu.pw.mini.jk.sg.uct.tree.UctNode

class FixedLengthUpdaterSpec extends WordSpec with Matchers with MockFactory {
  "FixedLengthUpdater" should {
    "bump visit counters for each node" in {
      val node1 = mock[UctNode[Int, Int]]
      val node2 = mock[UctNode[Int, Int]]
      val node3 = mock[UctNode[Int, Int]];

      inSequence {
        (node1.registerVisit _).expects(1)
        (node2.registerVisit _).expects(2)
        (node3.registerVisit _).expects(3)
      }

      val updater = new FixedLengthUpdater[Int, Int](3)

      updater.registerDecision(node1, 1)
      updater.registerDecision(node2, 2)
      updater.registerDecision(node3, 3)
    }

    "register payoffs only for nodes within limit" in {
      val node1 = mock[UctNode[Int, Int]]
      val node2 = mock[UctNode[Int, Int]]
      val node3 = mock[UctNode[Int, Int]];

      (node1.registerVisit _).expects(1);
      (node2.registerVisit _).expects(2);
      (node3.registerVisit _).expects(3);

      (node2.registerPayoff(_, _)).expects(2,2.5);
      (node3.registerPayoff(_, _)).expects(3,2.5)

      val updater = new FixedLengthUpdater[Int, Int](2)

      updater.registerDecision(node1, 1)
      updater.registerDecision(node2, 2)
      updater.registerDecision(node3, 3)
      updater.updatePayoffs(2.5, 4)
    }

    "register payoffs only for nodes within limit in mc" in {
      val node1 = mock[UctNode[Int, Int]]
      val node2 = mock[UctNode[Int, Int]]
      val node3 = mock[UctNode[Int, Int]];

      (node1.registerVisit _).expects(1);
      (node2.registerVisit _).expects(2);
      (node3.registerVisit _).expects(3);

      (node3.registerPayoff(_, _)).expects(3,2.5)

      val updater = new FixedLengthUpdater[Int, Int](2)

      updater.registerDecision(node1, 1)
      updater.registerDecision(node2, 2)
      updater.registerDecision(node3, 3)
      updater.registerMcMove(1, 4)
      updater.updatePayoffs(2.5, 4)
    }

    "register multiple payoffs only for nodes within limit in mc" in {
      val node1 = mock[UctNode[Int, Int]]
      val node2 = mock[UctNode[Int, Int]]
      val node3 = mock[UctNode[Int, Int]];

      (node1.registerVisit _).expects(1);
      (node2.registerVisit _).expects(2);
      (node3.registerVisit _).expects(3);

      (node3.registerPayoff(_, _)).expects(3,2.5);
      (node3.registerPayoff(_, _)).expects(3,4.5);

      val updater = new FixedLengthUpdater[Int, Int](2)

      updater.registerDecision(node1, 1)
      updater.registerDecision(node2, 2)
      updater.registerDecision(node3, 3)
      updater.registerMcMove(1, 4);
      updater.updatePayoffs(2.5, 4);
      updater.updatePayoffs(4.5, 5)
    }

    "work with mc phase longer than a queue" in {
      val updater = new FixedLengthUpdater[Int, Int](2)

      val node1 = mock[UctNode[Int, Int]]
      val node2 = mock[UctNode[Int, Int]]

      (node1.registerVisit _).expects(1);
      (node2.registerVisit _).expects(2);

      updater.registerDecision(node1, 1)
      updater.registerDecision(node2, 2)
      updater.registerMcMove(1, 3)
      updater.registerMcMove(1, 4)
      updater.registerMcMove(1, 5)
      updater.registerMcMove(1, 6)

      updater.updatePayoffs(3.2, 7)
    }

  }
}
