package rosetta

import scala.annotation.tailrec

object MoveToFront {
  
  private val R = 256

  
  private def symbolTable = (0 until R).map(_.toChar).mkString

  
  def encode(s: String): List[Int] = {
    encode(s, symbolTable)
  }

  
  def encode(s: String, symTable: String): List[Int] = {
    val table = symTable.toCharArray

    @inline @tailrec def moveToFront(ch: Char, index: Int, tmpout: Char): Int = {
      val tmpin = table(index)
      table(index) = tmpout
      if (ch != tmpin)
        moveToFront(ch, index + 1, tmpin)
      else {
        table(0) = ch
        index
      }
    }

    @tailrec def encodeString(output: List[Int], s: List[Char]): List[Int] = s match {
      case Nil => output
      case x :: xs => {
        encodeString(moveToFront(x, 0, table(0)) :: output, s.tail)
      }
    }
    encodeString(Nil, s.toList).reverse
  }

  
  def decode(ints: List[Int]): String = {
    decode(ints, symbolTable)   
  }

  
  def decode(lst: List[Int], symTable: String): String = {
    val table = symTable.toCharArray

    @inline def moveToFront(c: Char, index: Int) {
      for (i <- index-1 to 0 by -1)
        table(i+1) = table(i)
      table(0) = c
    }

    @tailrec def decodeList(output: List[Char], lst: List[Int]): List[Char] = lst match {
      case Nil => output
      case x :: xs => {
        val c = table(x)
        moveToFront(c, x)
        decodeList(c :: output, xs)
      }
    }
    decodeList(Nil, lst).reverse.mkString
  }

  def test(toEncode: String, symTable: String) {
		val encoded = encode(toEncode, symTable)
		println(toEncode + ": " + encoded)
		val decoded = decode(encoded, symTable)
		if (toEncode != decoded)
		  print("in")
		println("correctly decoded to " + decoded) 
	}
}


object RosettaCodeMTF extends App {
	val symTable = "abcdefghijklmnopqrstuvwxyz"
	MoveToFront.test("broood", symTable)
	MoveToFront.test("bananaaa", symTable)
	MoveToFront.test("hiphophiphop", symTable)
}