    -- |
    -- This module exports the core functions from the basic validation und simplification libraries.
    -- It also exports some helper functions for easier access to the validation functionality.

    module Text.XML.HXT.RelaxNG.Validator
      ( validateDocumentWithRelaxSchema
      , validateDocumentWithRelax
      , validateSchemaWithRelax
      , validateWithSpezification
      , validateSchemaWithSpezification

      , module Text.XML.HXT.RelaxNG.Validation
      , module Text.XML.HXT.RelaxNG.Simplification
      )
    where

    import Control.Arrow.ListArrows

    import Text.XML.HXT.DOM.Interface

    import Text.XML.HXT.Arrow.XmlArrow
    import Text.XML.HXT.Arrow.XmlState
    import Text.XML.HXT.Arrow.XmlState.TypeDefs

    import Text.XML.HXT.RelaxNG.BasicArrows
    import Text.XML.HXT.RelaxNG.Validation
    import Text.XML.HXT.RelaxNG.Simplification
    import Text.XML.HXT.RelaxNG.Schema        as S

    -- ------------------------------------------------------------

    {- |
       validate a document with a Relax NG schema

       * 1.parameter  : the system configuration option list for validation

       - 2.parameter  : the URI of the Relax NG Schema

       - arrow-input  : the document to be validated, namespaces must have been processed

       - arrow-output : the input document, or in case of validation errors, an empty document with status information in the root

    configuration options evaluated by validateDocumentWithRelaxSchema:

        * 'withRelaxCheckRestr'      : check Relax NG schema restrictions when simplifying the schema (default: on)

        - 'withRelaxValidateExtRef'  : validate a Relax NG schema referenced by a externalRef-Pattern (default: on)

        - 'withRelaxValidateInclude' : validate a Relax NG schema referenced by a include-Pattern (default: on)

    example:

    > validateDocumentWithRelaxSchema [withRelaxCheckRestr yes, withRelaxValidateExtRef no] "testSchema.rng"

    -}

    validateDocumentWithRelaxSchema :: SysConfigList -> String -> IOStateArrow s XmlTree XmlTree
    validateDocumentWithRelaxSchema config relaxSchema
        = ( withoutUserState
            $
            localSysEnv
            $
            configSysVars config
            >>>
            traceMsg 1 ( "start validating document with Relax NG schema: " ++ show relaxSchema )
            >>>
            ( ( ( validate' $< validateSchemaWithRelax relaxSchema)    -- try to validate, only possible if schema is o.k.
                >>>
                traceMsg 1 ( "validating document with Relax NG schema done" )
              )
              `orElse`
              ( setDocumentStatusFromSystemState "validating Relax NG schema"
                >>>
                traceMsg 1 ( "no validation done, Relax NG schema is not correct" )
              )
            )
          )
          `when`
          documentStatusOk                                 -- only do something when document status is ok
        where
        validate' schema
            = setDocumentStatusFromSystemState "read and build Relax NG schema"
              >>>
              validateDocumentWithRelax schema

    validateSchemaWithRelax         :: String -> IOSArrow XmlTree XmlTree
    validateSchemaWithRelax relaxSchema
        = traceMsg 2 ( "read and check Relax NG schema document: " ++ show relaxSchema )
          >>>
          readForRelax relaxSchema
          >>>
          ( let checkSchema = True in           -- test option in al
                if checkSchema
                then validateWithRelax S.relaxSchemaArrow `guards` this
                else this
          )
          >>>
          traceMsg 2 "create simplified schema"
          >>>
          ( (\ (b1, (b2, b3)) -> createSimpleForm b1 b2 b3)
            $<
            getSysVar (theRelaxCheckRestr     .&&&.
                       theRelaxValidateExtRef .&&&.
                       theRelaxValidateInclude
                      )
          )
          >>>
          traceDoc "simplified schema"
          >>>
          traceMsg 2 "collect and issue schema errors"
          >>>
          perform handleSimplificationErrors
          >>>
          resetStates
          >>>
          setDocumentStatusFromSystemState "validating Relax NG schema"
          >>>
          documentStatusOk
          >>>
          traceMsg 2 "Relax NG schema is o.k."

    handleSimplificationErrors      :: IOSArrow XmlTree XmlTree
    handleSimplificationErrors
        = traceDoc "simplification errors"
          >>>
          getErrors
          >>>
          getRngAttrDescr
          >>>
          arr ("Relax NG validation: " ++)
          >>>
          mkError c_err
          >>>
          filterErrorMsg

    {- | validate an XML document with respect to a Relax NG schema

       * 1.parameter  : the valid and simplified schema as XML tree

       - arrow-input  : the document to be validated

       - arrow-output : the validated and unchanged document or the empty document with status information set in the root node
    -}

    validateDocumentWithRelax       :: XmlTree -> IOSArrow XmlTree XmlTree
    validateDocumentWithRelax schema
        = ( traceMsg 1 "validate document with Relax NG schema"
            >>>
            perform ( validateWithRelax (constA schema) )
            >>>
            setDocumentStatusFromSystemState "validate document with Relax NG schema"
          )
          `when` documentStatusOk                           -- only do something when document status is ok

    -- ------------------------------------------------------------

    {- | Relax NG schema validation

        see 'validateSchemaWithRelax' and 'validateWithSpezification'

       * 1.parameter :  Relax NG schema file

       - arrow-input  :  Relax NG Specification in simple form
    -}

    validateSchemaWithSpezification :: String -> IOSArrow XmlTree XmlTree
    validateSchemaWithSpezification relaxSchema
        = validateWithSpezification "" relaxSchema

    {- | Document validation

    Validates a xml document with respect to a Relax NG schema

       * 1.parameter :  XML document

       - 2.parameter :  Relax NG schema file

    -}

    validateWithSpezification :: String -> String -> IOSArrow XmlTree XmlTree
    validateWithSpezification xmlDocument relaxSchema
        = validDoc $< listA (validateSchemaWithRelax relaxSchema)
        where
        validDoc [theSchema]
            | null xmlDocument
                = none
            | otherwise
                = ifA ( readForRelax xmlDocument
                        >>>
                        normalizeForRelaxValidation
                        >>>
                        validateRelax theSchema
                      )
                  none
                  ( err "Document is not valid with respect to Relax NG Schema" )
        validDoc _
            = err "Relax NG Schema not correct"

    -- ------------------------------------------------------------