<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    queryBinding="xslt2">
    <ns prefix="deltaxml" uri="http://www.deltaxml.com/ns/well-formed-delta-v1"/>
    <ns prefix="saxon" uri="http://saxon.sf.net/"/>
    <!-- include patterns from deltaV2 -->
    <include href="../../../projects/core/source/product/schematron/delta-common.sch#COMMON-root-rules"/>
    <include href="../../../projects/core/source/product/schematron/delta-common.sch#COMMON-subtree-delta-rules"/>
    <include href="../../../projects/core/source/product/schematron/delta-common.sch#COMMON-attribute-rules"/>
    <include href="../../../projects/core/source/product/schematron/delta-common.sch#COMMON-text-rules"/>

    <xsl:include href="../../../projects/core/source/product/schematron/delta-2-functions.xsl"/>
    <xsl:include href="../xsl/correct-with-order.xsl"/>
    <!-- the aboce include pulls in ../xsl/functions/combine-delta-parts.xsl, one of its functions is used here.
         With both includes there's a distracting warning message during schematron checking. -->

    <xsl:variable name="delta-version-order" select="tokenize(/*/@deltaxml:version-order, ', ')" as="xs:string*" /> 

    <!-- a pattern specific to deltaV2 -->
    <pattern id="all-format-merge-root-checks">
        <rule id="all-format-merge-root"
            context="/*">
            <include href="../../../projects/core/source/product/schematron/deltaV2.sch#V2-version-value"/>
            <!-- <assert id="V2-version-value"
                test="@deltaxml:version = '2.0'">Delta version must be 2.0</assert> -->
            <assert id="V2-merge-version-order"
                test="@deltaxml:version-order">There must be a deltaxml:version-order attribute</assert>
        </rule>
    </pattern>
    
    <pattern id="V2-merge-root-checks">
        <rule id="V2-content-type" context="/*">
            <assert id="V2-content-type-value"
                test="@deltaxml:content-type = ('merge-concurrent')">There must be a deltaxml:content-type attribute with the value 'merge-concurrent'</assert>
        </rule>
    </pattern>
    
    <pattern id="all-format-merge-delta-value-rules">
        <rule id="normal-elem-with-delta" context="*[@deltaxml:deltaV2]">
            <!-- redundant -->
            <report id="all-format-empty-delta"
                test="@deltaxml:deltaV2=''">Delta values may not be empty</report>
            <assert id="all-format-deltaV2-value-format"
                test="every $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) satisfies
                $v castable as xs:NMTOKEN">The following deltaV2 versions must be instances of NMTOKEN: <value-of 
                    select="deltaxml:report-string-join(
                      (for $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) return
                        if ($v castable as xs:NMTOKEN) then () else $v
                      ), 'and'
                    )"/>.</assert>
            <!-- redundant -->
            <!--<report id="V2-invalid-delta-characters"
                test="matches(@deltaxml:deltaV2, '[^ABC!=]')">Delta value contains invalid characters</report>-->
            <assert id="all-format-duplicate-version"
                test="count(distinct-values(tokenize(@deltaxml:deltaV2, '=|!='))) eq 
                count(tokenize(@deltaxml:deltaV2, '=|!='))">Delta versions must not be repeated within a deltaV2 attribute</assert>

            <assert test="every $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) satisfies $v = $delta-version-order"
                >Invalid deltaV2 version(s) detected for element at path <value-of select="saxon:path(.)"/>: <xsl:value-of 
                    select="deltaxml:report-string-join(
                    (for $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) return 
                    if ($v = $delta-version-order) then () else $v
                    ),
                    'and')" />.</assert>
            
            <assert test="count(deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) = count(distinct-values(deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)))"
                >DeltaV2 value contains duplicate versions for element at path <value-of select="saxon:path(.)"/>: <value-of 
                    select="deltaxml:report-string-join(
                    (for $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) return 
                    if (count($delta-version-order[.=$v]) le 1) then () else $v
                    ),
                    'and')" /> .</assert>
            
            <assert test="deltaxml:areVersionsInOrder(
                deltaxml:getDeltaV2VersionEquivClassRepresentatives(@deltaxml:deltaV2),
                $delta-version-order
                )">Invalid ordering of deltaV2 version between inequalities '!=' detected for element at path <value-of select="saxon:path(.)"/>: versions '<value-of 
                    select="deltaxml:report-string-join(
                    deltaxml:getDeltaV2VersionEquivClassRepresentatives(@deltaxml:deltaV2),
                    'and')" />' are in the wrong order.</assert>
            
            <assert test="every $ec in (deltaxml:getDeltaV2VersionEquivClasses(@deltaxml:deltaV2)) satisfies
                deltaxml:areVersionsInOrder($ec, $delta-version-order)"
                >Invalid ordering of deltaV2 version(s) between equalities '=' detected for element at path <value-of select="saxon:path(.)"/>: equivalence class(es) <value-of 
                    select="deltaxml:report-string-join(
                    (for $ec in (deltaxml:getDeltaV2VersionEquivClasses(@deltaxml:deltaV2)) return 
                    if (deltaxml:areVersionsInOrder($ec, $delta-version-order)) then () else $ec
                    ),
                    'and')" />' have invalid version orderings.</assert>

        </rule>
    </pattern>
    
    <!-- deltaV2 formal specific -->
    <pattern id="V2-merge-delta-value-rules">       
        <rule id="V2-elem-with-delta" context="*[@deltaxml:deltaV2]">
            <report id="V2-ancestor-deltas"
                test="ancestor::*[not(@deltaxml:deltaV2)]">All ancestors of an element with a delta attribute should also have delta attributes</report>
            <report id="V2-ancestor-versions"
                test="some $version in tokenize(@deltaxml:deltaV2, '=|!=') satisfies ancestor::*[not(contains(@deltaxml:deltaV2, $version))]">
                Every version in the delta value should be present in the delta value of all ancestor elements.
            </report>
        </rule>        
    </pattern>
    
    <pattern id="V2-merge-element-rules">
        <rule context="*/*[@deltaxml:deltaV2]">
            <assert test="exists(parent::*/@deltaxml:deltaV2)">The element at path <value-of 
                select="saxon:path(.)"/> has a deltaV2 value when its parent does not.</assert>
            
            <assert test="every $v in (deltaxml:getDeltaV2Versions(@deltaxml:deltaV2)) satisfies 
                $v = deltaxml:getDeltaV2Versions(parent::*/@deltaxml:deltaV2)">The element at path <value-of 
                    select="saxon:path(.)"/> has a deltaV2 value that has version(s) that the parent does not.</assert>
            
            <assert test="deltaxml:isChildDeltaV2ConsitentWithItsParent(@deltaxml:deltaV2, parent::*/@deltaxml:deltaV2)"
                >The element at <value-of select="saxon:path(.)"/> has a deltaV2 value that is inconsistent with its parent.</assert>
            
        </rule>
    </pattern>
    
    <pattern id="V2-merge-element-rules-2">
        <rule context="*[matches(@deltaxml:deltaV2, '!=')]">
            <assert test="@deltaxml:deltaV2 eq deltaxml:reorderDeltaParts(deltaxml:combine(@deltaxml:deltaV2, child::*/@deltaxml:deltaV2))">The element at path <value-of 
                    select="saxon:path(.)"/> has an invalid deltaV2 with respect to the child deltas.  The deltaV2 value is <value-of
                    select="@deltaxml:deltaV2"/> and should be <value-of 
                    select="deltaxml:reorderDeltaParts(deltaxml:combine(@deltaxml:deltaV2, child::*/@deltaxml:deltaV2))"/>.</assert>
        </rule>
    </pattern>
</schema>