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#>
PREFIX iter: <http://w3id.org/sparql-generate/iter/>
PREFIX schema: <http://schema.org/>

BASE <https://saref.etsi.org/documentation/>

TEMPLATE <objectProperties.rqg>( ?ontology, ?lang ) { 

  """\n<div id='objectproperties'>
  <h2>{ fun:property(<en.properties>, 'objectproperties') }</h2>""" 

  BOX { 

    # toc
    TEMPLATE <templates/toc.rqg>( ?lang, ?op )
    WHERE {
      ?op a owl:ObjectProperty
      FILTER( ISURI(?op) ) 
    } ORDER BY ?op . 

    # description
    TEMPLATE {
      "\n<div id='{fun:prefixedIRI(?op)}' class='entity'>" BOX {
        
        "<a name='{?op}'></a>"
          "\n<h3>" 

            TEMPLATE { ?langLabel 
            } ITERATOR iter:call-select(<getLabel.rqg>, ?op, ?lang) AS ?langLabel .

           <sup.rqg>(<en.properties>, 'objectproperty') 
          
           <backlink.rqg>("objectproperties", "Object Property") 
          "</h3>"
        
        

          "\n<p><strong>IRI:</strong> { ?op }</p>"

          TEMPLATE {
            "\n<div class='comment'><p>{?comment}</p></div>"
          } DISTINCT WHERE {
            OPTIONAL { ?op ( rdfs:comment|prov:definition|skos:definition | obo:IAO_0000115) ?comment }
            FILTER(LANG(?comment) = str(?lang) || LANG(?comment) = "" )
          } .
        
          TEMPLATE {
            "\n<div class='comment'><p>{?comment}</p></div>"
          } DISTINCT WHERE {
            OPTIONAL { ?op (dc:description|dcterms:description) ?comment }
            FILTER(LANG(?comment) = str(?lang) || LANG(?comment) = "" )
          } .

          # should add more metadata here (see LODE)
          #<xsl:call-template name="get.version" />
          #<xsl:call-template name="get.author" />
          #<xsl:call-template name="get.original.source" />
          #<xsl:call-template name="get.source" />
          #<xsl:call-template name="get.termStatus" />
          #<xsl:call-template name="get.deprecated" />
          #<xsl:call-template name="get.rationale" />
          #<xsl:call-template name="get.example" />

        
          # See https://www.w3.org/TR/owl2-quick-reference/#Properties 
          # Object Property Axioms 
          TEMPLATE {
            "\n<div class='description'><dl>" BOX {

              # characteristics property
              TEMPLATE {
                before = "\n<p><strong>{ fun:property(<en.properties>, 'hascharacteristics') }:</strong> " ;
                  fun:property(<en.properties>, ?label)
                ; separator = ", "
                ; after = "</p>"
              } DISTINCT WHERE {
                VALUES (?type ?label)  { 
                  ( owl:FunctionalProperty 'functional' )
                  ( owl:InverseFunctionalProperty 'inversefunctional' )
                  ( owl:ReflexiveProperty 'reflexive' )
                  ( owl:IrreflexiveProperty 'irreflexive' )
                  ( owl:SymmetricProperty 'symmetric' )
                  ( owl:AsymmetricProperty 'asymmetric' )
                  ( owl:TransitiveProperty 'transitive' )
                }
                ?op a ?type .
              } .

              # equivalent properties
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hasequivalentproperties') }</dt><dd>" ;
                  TEMPLATE <propertyDescription.rqg>( <en.properties> , ?op2 ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                { ?op owl:equivalentProperty ?op2 }
                UNION
                { ?op2 owl:equivalentProperty ?op }
              } .

              # hassuperproperties
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hassuperproperties') }</dt><dd>" ;
                  TEMPLATE <propertyDescription.rqg>( <en.properties> , ?op2 ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op rdfs:subPropertyOf ?op2
              } .

              # hassubproperties
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hassubproperties') }</dt><dd>" ;
                  TEMPLATE <propertyDescription.rqg>( <en.properties> , ?op2 ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op2 rdfs:subPropertyOf ?op
              } .

              # property domain
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hasdomain') }</dt><dd>" ;
                  TEMPLATE <classDescription.rqg>( <en.properties> , ?c , true ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op rdfs:domain ?c
              } .

              # property domain includes
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'domainIncludes') }</dt><dd>" ;
                  TEMPLATE <classDescription.rqg>( <en.properties> , ?c , true ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op schema:domainIncludes ?c
              } .

              # property range
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hasrange') }</dt><dd>" ;
                  TEMPLATE <classDescription.rqg>( <en.properties> , ?c , true ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op rdfs:range ?c
              } .

              # property range includes
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'rangeIncludes') }</dt><dd>" ;
                  TEMPLATE <classDescription.rqg>( <en.properties> , ?c , true ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op schema:rangeIncludes ?c
              } .

              # inverse properties
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'isinverseof') }</dt><dd>" ;
                  TEMPLATE <propertyDescription.rqg>( <en.properties> , ?op2 ) . 
                ; separator = ", "
                ; after = "</dd>"
              } DISTINCT WHERE {
                { ?op owl:inverseOf ?op2 }
                UNION
                { ?op2 owl:inverseOf ?op }
                FILTER( ISURI(?op2) ) 
              } .

              # property chains
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'hassubpropertychains') }</dt><dd>" ;
                TEMPLATE <propertyDescription.rqg>(<en.properties> , ?op1 ) .
                TEMPLATE <subSubPropertyChain.rqg>( <en.properties>, ?c1 ) .
                ; separator = "<br/> "
                ; after = "</dd>"
              } DISTINCT WHERE {
                ?op owl:propertyChainAxiom ?c0 .
                ?c0 rdf:first ?op1 .
                ?c0 rdf:rest ?c1 .
              } .

              # disjoint properties
              TEMPLATE {
                before = "\n<dt>{ fun:property(<en.properties>, 'isdisjointwith') }</dt><dd>" ;
                  TEMPLATE <propertyDescription.rqg>( <en.properties> , ?op2 ) . 
                ; separator = ", "
                ; after = "</dd>"
              } WHERE {
                { ?op owl:propertyDisjointWith ?op2 }
                UNION
                { ?op2 owl:propertyDisjointWith ?op }
              } .

            } "\n</dl></div>"
          } WHERE {
            
          } .





      } "\n</div>"



    } DISTINCT WHERE {
      ?op a owl:ObjectProperty
      FILTER( ISURI(?op) ) 
    } ORDER BY ?op . 


  }
  "\n</div>"

}