package templates

import scala.collection.mutable
import scala.util.{Success, Try}
import scala.xml.{NodeSeq, Text}

trait Logger {
  this: Template =>

  private[this] lazy val data = {
    val m: mutable.LinkedHashMap[Int, mutable.Queue[(String, String, mutable.LinkedHashMap[Int, (String, String)])]] =
      mutable.LinkedHashMap()
    val items = source \\ "_"

    for (i <- items) {
      if (i.attributes.nonEmpty || (i.child.length == 1)) {
        val idx = i.hashCode
        val attr: mutable.LinkedHashMap[Int, (String, String)] =
          if (i.attributes.nonEmpty) mutable.LinkedHashMap() else null
        val text = if (i.child.nonEmpty && !i.child.head.text.contains("\n")) i.child.head.text else null

        m.get(idx) match {
          case None =>
            m(idx) = mutable.Queue((i.label, text, attr))
          case _ =>
            m(idx).enqueue((i.label, text, attr))
        }

        if (i.attributes.nonEmpty) {
          for (a <- i.attributes) {
            m(idx).last._3(a.value.hashCode) = (a.key, a.value.text)
          }
        }
      }
    }

    m
  }

  override protected[this] def get(content: NodeSeq, attr: String = null, idx: Int = 0): Text =
    Try { content(idx) } match {
      case Success(v) =>
        var res = Text(v.text)

        if (attr != null) v.attribute(attr) match {
          case None =>
            res = Text(msgNotFound)
          case o =>
            data(v.hashCode).head._3 -= o.get.hashCode
            res = Text(o.get.text)
        } else if (data(v.hashCode).nonEmpty) {
          if (data(v.hashCode).head._3 != null) {
            val e = data(v.hashCode).head.copy(_2 = null)

            data(v.hashCode).enqueue(e)
          }
          data(v.hashCode).dequeue()
        }

        res
      case _ => Text(msgNotFound)
  }

  override def info(msg: String): String = {
    val additionalInfo = data
      .filter { case (_, v) => v.nonEmpty }
      .toVector
      .flatMap { case (_, v ) => v }
      .filter { case (_, v, m) => v != null || (m != null && m.nonEmpty) }
      .map {
        case (t, v, m) => s"tag: $t, value: ${if (v != null) v else ""}" +
          (if (m != null && m.nonEmpty) ", " + m.toVector.map { case (k, v1) => v1 }.map {
            case (k1, v2) => s"attr: $k1, value: $v2"
          }.mkString(", ") else "")
      }
      .mkString("\n")

    s"$msg\nNot used:\n$additionalInfo"
  }
}
