package xmlvalid

import java.net.URL

import javax.xml.XMLConstants
import javax.xml.parsers.SAXParser
import javax.xml.parsers.SAXParserFactory
import javax.xml.validation.SchemaFactory

import scala.xml._
import scala.xml.factory.XMLLoader
import scala.xml.parsing.{ConsoleErrorHandler, NoBindingFactoryAdapter}

/** Provides operations with xml checked against schema
  *
  * {{{
  * scala> val xml = XMLValid("schema.xsd").loadFile("source.xml")
  * }}}
  *
  * @constructor Creates instance from path to xsd schema
  * @param xsdPath path to xsd file (URL)
  */
class XMLValid(xsdPath: URL) extends XMLLoader[Node] {
  private[this] val schema = SchemaFactory
    .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
    .newSchema(xsdPath)

  override def adapter: NoBindingFactoryAdapter with ConsoleErrorHandler =
    new NoBindingFactoryAdapter with ConsoleErrorHandler {

      override def error(ex: SAXParseException): Unit = throw ex

      override def fatalError(ex: SAXParseException): Unit = throw ex
    }

  override def parser: SAXParser = {
    val f = SAXParserFactory.newInstance

    f.setNamespaceAware(true)
    f.setFeature("http://xml.org/sax/features/namespace-prefixes", true)
    f.setSchema(schema)
    f.newSAXParser
  }
}

/** Factory for [[XMLValid]] instances. */
object XMLValid {

/** Creates a ValidXML instance with given xsd schema
  *
  * @param xsdPath path to xsd file (URL)
  * @return XMLValid instance
  */
  def apply(xsdPath: URL) = new XMLValid(xsdPath)
}