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

import org.scalatest.{Matchers, WordSpec}
import pl.edu.pw.mini.sg.compactlp.model.GridPosition

class SparseUtilsSpec extends WordSpec with Matchers  {
  "The SparseUtils object" should {
      "provide a positionToSparse method" which {
        "does not change the position for sparsity == 1" in {
          val result = SparseUtils.positionToSparse(GridPosition(-4, 6), 1)
          result should equal (GridPosition(-4, 6))
        }

        "returns (0, 0) for (0, 0) regardless of sparsity" in {
          val results = Seq(1, 2, 4).map(SparseUtils.positionToSparse(GridPosition(0,0), _))
          results should contain only GridPosition(0, 0)
        }

        "returns (1, -1) for input (4, -7) and sparsity 4" in {
          val result = SparseUtils.positionToSparse(GridPosition(4, -7), 4)
          result should equal (GridPosition(1, -1))
        }

        "returns (1, 8) for input (2, 15) and sparsity 2" in {
          val result = SparseUtils.positionToSparse(GridPosition(2, 15), 2)
          result should equal (GridPosition(1, 8))
        }
    }

    "provide a sparseToPosition method" which {
      "does not change the position for sparsity == 1" in {
        val result = SparseUtils.sparseToPosition(GridPosition(5, -13), 1)
        result should equal (GridPosition(5, -13))

      }
      "returns inner point of aggregated square for odd sparsity" in {
        val result = SparseUtils.sparseToPosition(GridPosition(3, -2), 3)
        result should equal (GridPosition(8, -7))
      }

      "returns left upper point of inner 2 x 2 square in aggregated square for even sparsity" in {
        val result = SparseUtils.sparseToPosition(GridPosition(2, -1), 4)
        result should equal (GridPosition(6, -6))
      }
    }

    "provide a getSparseGridForPosition method" which {
      "returns only original position for sparsity == 1" in {
        val result = SparseUtils.getSparseGridForPosition(GridPosition(-5, 8), 1)
        result should have size 1
        result should contain only GridPosition(-5, 8)
      }

      "returns sparsity * sparsity elements" in {
        val lengths = Seq(1, 2, 4).map(SparseUtils.getSparseGridForPosition(GridPosition(1, 2), _).length)
        lengths should contain inOrderOnly (1, 4, 16)
      }

      "returns elements around position for odd sparsity" in {
        val elements = SparseUtils.getSparseGridForPosition(GridPosition(-1, 3), 3)
        elements should contain allOf (
          GridPosition(-2, 2), GridPosition(-1, 2), GridPosition(0, 2),
          GridPosition(-2, 3), GridPosition(-1, 3), GridPosition(0, 3),
          GridPosition(-2, 4), GridPosition(-1, 4), GridPosition(0, 4))
      }

      "returns elements around position and position+1 for even sparsity" in {
        val elements = SparseUtils.getSparseGridForPosition(GridPosition(5, 2), 4)
        elements should contain allOf (
          GridPosition(4, 1), GridPosition(5, 1), GridPosition(6, 1), GridPosition(7, 1),
          GridPosition(4, 2), GridPosition(5, 2), GridPosition(6, 2), GridPosition(7, 2),
          GridPosition(4, 3), GridPosition(5, 3), GridPosition(6, 3), GridPosition(7, 3),
          GridPosition(4, 4), GridPosition(5, 4), GridPosition(6, 4), GridPosition(7, 4),
                                        )
      }
    }

    "provide a sparsePathToReal method" which {
      "returns path with length == timeSteps" in {
        val sparsePath = (1.0, Seq(GridPosition(2, 3), GridPosition(4, 4), GridPosition(5, 2)))
        val (_, path) = SparseUtils.sparsePathToReal(sparsePath, 2, 5)
        path should have size 5
      }

      "returns the same path for sparsity == 1" in {
        val sparsePath = (1.0, Seq(GridPosition(2, 3), GridPosition(4, 4), GridPosition(5, 2)))
        val (_, path) = SparseUtils.sparsePathToReal(sparsePath, 1, 3)
        path should contain inOrderOnly (GridPosition(2, 3), GridPosition(4, 4), GridPosition(5, 2))
      }

      "does not alter probability" in {
        val sparsePath = (0.3, Seq(GridPosition(2, 3), GridPosition(4, 4), GridPosition(5, 2)))
        val (probability, _) = SparseUtils.sparsePathToReal(sparsePath, 4, 12)
        probability should equal(0.3)
      }

      "returns extended path for sparsity larger than one" in {
        val sparsePath = (1.0, Seq(GridPosition(-1, 0), GridPosition(-2, 1), GridPosition(0, 3)))
        val (_, path) = SparseUtils.sparsePathToReal(sparsePath, 2, 5)
        path should contain inOrderOnly (GridPosition(-3, -1), GridPosition(-4, 0), GridPosition(-5, 1),
          GridPosition(-3, 3), GridPosition(-1, 5))
      }
    }
  }

}
