PREFIX st:   <http://ns.inria.fr/sparql-template/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX fun: <http://w3id.org/sparql-generate/fn/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX obo: <http://purl.obolibrary.org/obo/>
PREFIX swrl: <http://www.w3.org/2003/11/swrl#>
PREFIX prov: <http://www.w3.org/ns/prov#>
 
BASE <https://saref.etsi.org/documentation/>
 
TEMPLATE  <term/classDescription.rqg>( ?class , ?first ) {

  TEMPLATE {
    "<a href='#{fun:prefixedIRI(?class)}' title='{?labelStr}: {?commentStr}'>{fun:prefixedIRI(?class)}</a>"
    "<sup title='{ fun:property(<en.properties>, 'class') }' class='type-c'>c</sup>"
  } 
  WHERE {
    FILTER(ISURI(?class))
    OPTIONAL {
    ?class rdfs:label ?label ;
       rdfs:comment ?comment }
    BIND( IF(BOUND(?label), ?label, "<<no label>>") AS ?labelStr )
    BIND( IF(BOUND(?comment), ?comment, "<<no comment>>") AS ?commentStr )
  } .

  TEMPLATE {

    IF(!?first, " (", "")

    # see http://www.w3.org/TR/2012/REC-owl2-primer-20121211/#Classes_and_Instances
    TEMPLATE {
      TEMPLATE <term/classDescription.rqg>( ?C , false ) .
      ; separator= " <span class='logic'>and</span> "
    }
    
    WHERE {
      ?class owl:intersectionOf / rdf:rest* / rdf:first ?C
    } .

    TEMPLATE {
      TEMPLATE <term/classDescription.rqg>( ?C , false ) .
      ; separator= " <span class='logic'>or</span> "
    }
    
    WHERE {
      ?class owl:unionOf / rdf:rest* / rdf:first ?C
    } .

    TEMPLATE {
      " <span class='logic'>not</span> "
      TEMPLATE <term/classDescription.rqg>( ?C , false ) .
    }
    
    WHERE {
      ?class owl:complementOf ?C
    } .

    TEMPLATE { 
      before= "one of \{ " ;
      TEMPLATE <term/individualAndLiteralDescription.rqg>( ?ni ) .
      ; separator= ", "
      ; after= " } " 
    }
    
    WHERE {
      ?class owl:oneOf / rdf:rest* / rdf:first ?ni
    } .

    # object property restrictions
    TEMPLATE {

      # universal
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>only</span> "
        TEMPLATE <term/classDescription.rqg>( ?only , false ) .
      }
      WHERE {
        ?class owl:allValuesFrom ?only 
      } .

      # existential
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>some</span> "
        TEMPLATE <term/classDescription.rqg>( ?some , false ) .
      }
      WHERE {
        ?class owl:someValuesFrom ?some
      } .

      # individual value
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>value</span> "
        TEMPLATE <term/individualAndLiteralDescription.rqg>( ?value ) .
      }
      WHERE {
        ?class owl:hasValue ?value
      } .

      # local reflexivity
      TEMPLATE {
        " <span class='logic'>has self</span> "
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
      }
      WHERE {
        ?class owl:hasSelf true
      } .

      # exact cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>exactly</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:cardinality ?cardinality .
      } .

      # qualified exact cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>exactly</span> { ?cardinality } "
        TEMPLATE <term/classDescription.rqg>( ?C , false ) .
      }
      WHERE {
        ?class owl:qualifiedCardinality ?cardinality ;
          owl:onClass ?C .
      } .

      # maximum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>max</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:maxCardinality ?cardinality .
      } .

      # qualified maximum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>max</span> { ?cardinality } "
        TEMPLATE <term/classDescription.rqg>( ?C , false ) .
      }
      WHERE {
        ?class owl:maxQualifiedCardinality ?cardinality ;
          owl:onClass ?C .
      } .

      # minimum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>min</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:minCardinality ?cardinality .
      } .

      # qualified minimum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>min</span> { ?cardinality } "
        TEMPLATE <term/classDescription.rqg>( ?C , false ) .
      }
      WHERE {
        ?class
          owl:minQualifiedCardinality ?cardinality ;
          owl:onClass ?C .
      } .

    } 
    WHERE {
      ?class owl:onProperty ?property .
      { ?property a owl:ObjectProperty } 
      UNION 
      { ?property owl:inverseOf [] } 
      UNION 
      { [] owl:inverseOf ?property } 
      UNION 
      {
        FILTER( ?property = owl:topObjectProperty || ?property = owl:bottomObjectProperty)
      } 
    } LIMIT 1 .

    # data property restrictions
    TEMPLATE {

      # universal
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>only</span> "
        TEMPLATE <term/dataRangeDescription.rqg>( ?only ) .
      }
      WHERE {
        ?class owl:allValuesFrom ?only 
      } .

      # existential
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>some</span> "
        TEMPLATE <term/dataRangeDescription.rqg>( ?some ) .
      }
      WHERE {
        ?class owl:someValuesFrom ?some
      } .

      # individual value
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>value</span> "
        TEMPLATE <term/individualAndLiteralDescription.rqg>( ?value ) .
      }
      WHERE {
        ?class owl:hasValue ?value
      } .

      # exact cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>exactly</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:cardinality ?cardinality .
      } .

      # qualified exact cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>exactly</span> { ?cardinality } "
        TEMPLATE <term/dataRangeDescription.rqg>( ?D  ) .
      }
      WHERE {
        ?class owl:qualifiedCardinality ?cardinality ;
          owl:onDataRange ?D .
      } .

      # maximum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>max</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:maxCardinality ?cardinality .
      } .

      # qualified maximum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>max</span> { ?cardinality } "
        TEMPLATE <term/dataRangeDescription.rqg>( ?D ) .
      }
      WHERE {
        ?class owl:maxQualifiedCardinality ?cardinality ;
          owl:onDataRange ?D .
      } .

      # minimum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>min</span> { ?cardinality } "
      }
      WHERE {
        ?class owl:minCardinality ?cardinality .
      } .

      # qualified minimum cardinality
      TEMPLATE {
        TEMPLATE <term/propertyDescription.rqg>( ?property ) .
        " <span class='logic'>min</span> { ?cardinality } "
        TEMPLATE <term/dataRangeDescription.rqg>( ?D ) .
      }
      WHERE {
        ?class owl:minQualifiedCardinality ?cardinality ;
          owl:onDataRange ?D .
      } .

    } 
    WHERE {
      ?class owl:onProperty ?property .
      { ?property a owl:DatatypeProperty } 
      UNION 
      {
        FILTER( ?property = owl:topDataProperty || ?property = owl:bottomDataProperty)
      } 
    } .

    IF(!?first, ")", "")

  } 
  WHERE {
    FILTER(ISBLANK(?class))    
  } .


}