package templates

import org.scalatest._
import xmlvalid._

import scala.xml.{Elem, Node, XML}

class TemplateSpec extends WordSpec {
  "XMLValid for RTS example" should {
    "successfully loadFile(xmlPath) with well formed and valid xml" in {
      val validXml = XMLValid(getClass.getResource("/templates/rts/fpml-recordkeeping-merged-schema.xsd"))
      val xml = validXml.load(getClass.getResource("/templates/rts/Example repo RTS.xml"))
      assert(xml.isInstanceOf[Node])
    }
  }

  it should {
    "throw exception in loadFile(xmlPath) with well formed but invalid xml" in {
      assertThrows[Exception] {
        val validXml = XMLValid(getClass.getResource("/templates/rts/fpml-recordkeeping-merged-schema.xsd"))
        val xml = validXml.load(getClass.getResource("/templates/rts/Example repo RTS invalid.xml"))
      }
    }
  }

  "XMLValid for NSD example" should {
    "successfully loadFile(xmlPath) with well formed and valid xml" in {
      val validXml = XMLValid(getClass.getResource("/templates/nsd/nsd-ext-merged-schema.xsd"))
      val xml = validXml.load(getClass.getResource("/templates/nsd/Example repo NSD.xml"))
      assert(xml.isInstanceOf[Node])
    }
  }

  it should {
    "throw exception in loadFile(xmlPath) with well formed but invalid xml" in {
      assertThrows[Exception] {
        val validXml = XMLValid(getClass.getResource("/templates/nsd/nsd-ext-merged-schema.xsd"))
        val xml = validXml.load(getClass.getResource("/templates/nsd/Example repo NSD invalid.xml"))
      }
    }
  }

  class MockTemplate(source: Node) extends Template(source) {
    def template: Node = {
      <document
      xmlns="https://www.w3schools.com"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="https://www.w3schools.com test_valid.xsd">
        <nonpublicExecutionReport>
          <trade>
            <tradeHeader>{ get(source \\ "tradeHeader") }</tradeHeader>
            <repo>
              <title>{ get(source \\ "repo" \ "title") }</title>
              <from href={ get(source \\ "repo" \ "from", "href") }>
                { get(source \\ "repo" \ "from") }
              </from>
              <to href={ get(source \\ "repo" \ "to", "href") }>
                { get(source \\ "repo" \ "notExist") }
              </to>
            </repo>
            <notFoundpart>{ get(source \\ "notFoundpart") }</notFoundpart>
            <notFoundpartNested1>
              <noElem>{ get(source \\ "notFoundpartNested1" \ "noElem") }</noElem>
              <noAttr href={ get(source \\ "notFoundpartNested1" \ "noAttr", "href") } />
              <noAttrAndElem href={ get(source \\ "notFoundpartNested1" \ "noAttrAndElem", "href") }>
                { get(source \\ "notFoundpartNested1" \ "noAttrAndElem") }
              </noAttrAndElem>
            </notFoundpartNested1>
            <notFoundpartNested2>
              <notFoundPartNested21>
                <noElem>{ get(source \\ "notFoundpartNested21" \ "noElem") }</noElem>
                <noAttr href={ get(source \\ "notFoundpartNested21" \ "noAttr", "href") } />
                <noAttrAndElem href={ get(source \\ "notFoundpartNested21" \ "noAttrAndElem", "href") }>
                  { get(source \\ "notFoundpartNested21" \ "noAttrAndElem") }
                </noAttrAndElem>
              </notFoundPartNested21>
            </notFoundpartNested2>
          </trade>
        </nonpublicExecutionReport>
      </document>
    }

    def isStraight: Boolean = true
  }

  "Template" should {
    "render valid xml against schema" in {
      val sourceXml: Node = XML.load(getClass.getResource("/templates/general/test_valid.xml"))
      val outputXml = new MockTemplate(sourceXml).render
      val checkedXml = XMLValid(getClass.getResource("/templates/general/test_valid.xsd")).loadString(outputXml.mkString)

      assert(checkedXml.isInstanceOf[Node])
    }
  }

  it should {
    "choose right Template class and create template instance using source" in {
      implicit def templateFactory(source: Node): Template = {
        (source \\ "trade").head.child.filter {
          case v: Elem => true
          case _ => false
        }(1).label match {
          case "repo" => new MockTemplate(source)
          case v => throw new Exception("Undefined trade type")
        }
      }

      val sourceXml: Node = XML.load(getClass.getResource("/templates/general/test_valid.xml"))
      val template = Template(sourceXml)

      assert(template.isInstanceOf[Template])
    }
  }

  it should {
    "throw Exception if Template type is undefined" in {
      implicit def templateFactory(source: Node): Template = {
        (source \\ "trade").head.child.filter {
          case v: Elem => true
          case _ => false
        }(1).label match {
          case "bond" => new MockTemplate(source)
          case v => throw new Exception("Undefined trade type")
        }
      }

      val sourceXml: Node = XML.load(getClass.getResource("/templates/general/test_valid.xml"))

      assertThrows[Exception] {
        val template = Template(sourceXml)
      }
    }
  }
}


