package pl.edu.pw.mini.jk.lib

import argonaut.{ Argonaut, CodecJson, CursorHistory, DecodeJson, DecodeResult, Parse }

object JsonHelpers {
  def readOneFromSet[T](possibilities: PartialFunction[String, T]) : DecodeJson[T] =
    DecodeJson(node => 
      node.as[String].flatMap(n =>
        possibilities.lift(n) match {
          case Some(n) => DecodeResult.ok(n)
          case None => DecodeResult.fail("unknown value "+n, node.history)
        }
      ))


  def enumerationCodec[T](elements: List[(String, T)]) : CodecJson[T] = CodecJson[T](
    (v: T) => elements.find(p => p._2 == v).map(p => Argonaut.jString(p._1)).getOrElse{throw new RuntimeException("Don't know how to encode "+ v)},
    c => c.as[String].flatMap(s =>
      elements.find(p => p._1 == s).map((p : (String, T)) =>
        DecodeResult.ok(p._2)).getOrElse(DecodeResult.fail("Unknown value"+ s, c.history)))
  )

  class DecodeResultWithException[T](result: DecodeResult[T]) {
    def getWithException : T = result.toEither match {
      case Right(value) => value
      case Left(error) => throw new RuntimeException("Json parsing error "+ error)
    }
  }
  import scala.language.implicitConversions
  implicit def decodeResultWithException[T](r: DecodeResult[T]) = new DecodeResultWithException(r)


  private def pairToError[T](p: String,  h: CursorHistory) : T = throw new RuntimeException("Json decode failed (" + p+"," +h +")")
  
  def readWithException[T](json: String)(implicit decoder: DecodeJson[T]) : T =
    Parse.decodeWith[T, T](
      json, identity,
      s => throw new RuntimeException("Json parser failed: "+ s),
      pairToError)

}

