@prefix n0: <https://arspec.org/ars/perspec/1/styles#> .
@prefix sel: <https://arspec.org/ars/perspec/1/selector_attributes#> .
@prefix set: <https://arspec.org/ars/perspec/1/set_attributes#> .
@prefix items: <https://arspec.org/ars/perspec/1/content_items#> .
@prefix elem: <https://arspec.org/ars/perspec/1/style_element#> .
@prefix ars: <https://arspec.org/ars/spec/1/schema#> .
@prefix av: <https://arspec.org/ars/spec/1/schema/view#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# == The Styles family ==
#
# One perspective and its four services. Styles is what stands on the
# screen, and it is only ever run over a file: a tab of the file's, and no
# lens (ars:inLensList false). The four services each answer about one node
# of a style, handed to them as the subject of a row with nothing else in it,
# and are only ever run that way: no tab of the file's (ars:inFileTabs
# false), no box in the lens list, and ars:serviceOf naming the perspective
# whose invocations run them.
#
#   Selector Attributes     what a style's av:select node states — the
#                           conditions it requires
#   Set Attributes          what its av:set node states — the properties it
#                           sets — and under the av:content among them,
#                           Content Items
#   Content Items           a node's av:item rows and nothing else of it, in
#                           av:order and movable, each item read through
#                           Style Element
#   Style Element           what one item states — its element, its role,
#                           its name, never its number, which Content Items
#                           keeps — and under an av:content of its own,
#                           a layout's, Content Items again: one shape of
#                           list, read the same at every depth
#
# The two attribute lists are one level each, where a single Attributes+
# used to read both nodes as a tree: what a selector states and what a style
# sets are different vocabularies, and a list of its own lets each start a
# new statement where that vocabulary starts — and lets the one property
# whose value is a list, av:content, be read as the ordered list it is
# rather than as one more anonymous node.

# == Styles ==
#
# A file's stylesheet as records: one per av:Style node, in av:order, each
# with its label, its selector and the properties it sets in sections beneath
# it — the styles a file carries, edited where the file is.
#
# The root's records are the file's av:Style subjects, placed by their
# av:order (ars:sortBy ars:order): the order query says where a style's
# number is — the statement about that style whose predicate is av:order —
# and said that way the number can be written as well as found, which is
# what lets a style be moved up and down and gives a new one the number
# after the last. Label, Selector and Set Attributes are av:Form: no
# heading, the source's name leading the value where the pinned predicate
# would have stood; the label is a floor of 1, made with the style.
#
# Ships switched off: most files carry no styles, and a tab that would stand
# empty on them waits in the perspectives screen, one checkbox away.

n0:perspec a ars:Perspective ;
    ars:title "Styles" ;
    ars:description "Each av:Style node with its label, order, selector and stated properties in separate sections." ;
    ars:activeByDefault false ;
    ars:inLensList false ;
    ars:rootDataSource n0:ds_styles .

n0:ds_styles a ars:DataSource ;
    ars:subjectVisible true ;
    ars:distinctBy rdf:subject ;
    ars:sortBy ars:order ;
    ars:subjectOnClick ars:edit ;
    # A style is a node with no name: nothing points at one, and a name in
    # the file's namespace would be a name to nothing.
    ars:adding [
        a ars:RowAction ;
        ars:subjectDefaultValue [ a ars:BlankValue ]
    ] ;
    ars:orderQuery [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "order" ]
        ]
    ] ;
    ars:filter [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
        ars:op ars:typeIs ;
        ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "Style" ]
    ] ;
    ars:child n0:ds_label, n0:ds_select, n0:ds_set .

# The one-valued parts of a style — each pinned to its predicate by the
# filter, at most one row, and one made along with the style.

n0:ds_label a ars:DataSource, av:Form ;
    ars:order 0 ;
    ars:label "Label" ;
    ars:objectVisible true ;
    ars:objectTypeConstraint xsd:string ;
    ars:maxCount 1 ;
    ars:minCount 1 ;
    ars:filter [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "http://www.w3.org/2000/01/rdf-schema#" ; ars:localName "label" ]
        ]
    ] .

# The two nodes of a style. The value shown is the anonymous node itself, so
# a click on it looks into it rather than opening an editor on a label nobody
# chose (ars:objectOnClick ars:expand). The selector is read wherever the
# style's statements may stand — the ontologies the file imports, the user's
# own data and the app's defaults beside the file itself.

n0:ds_select a ars:DataSource, av:Form ;
    ars:order 1 ;
    ars:label "Selector" ;
    ars:objectVisible true ;
    ars:objectOnClick ars:expand ;
    ars:objectTypeConstraint ars:term ;
    ars:maxCount 1 ;
    ars:minCount 1 ;
    ars:loadImportedFiles true ;
    ars:loadUserData true ;
    ars:loadAppDefaults true ;
    ars:filter [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "select" ]
        ]
    ] ;
    ars:child n0:inv_select .

n0:ds_set a ars:DataSource, av:Form ;
    ars:order 2 ;
    ars:label "Set Attributes" ;
    ars:objectVisible true ;
    ars:objectOnClick ars:expand ;
    ars:objectTypeConstraint ars:term ;
    ars:maxCount 1 ;
    ars:minCount 1 ;
    ars:filter [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "set" ]
        ]
    ] ;
    ars:child n0:inv_set .

# What each node states, read by the service written for it: handed the node
# as its subject — the invoking row's object where the subject was — and
# nothing in the other two parts.
# The Add stands where the style is a focused rendering — opened in place, or
# on its page — as the parts above it already do.

n0:inv_select a ars:Invocation ;
    ars:order 0 ;
    ars:perspective sel:perspec ;
    ars:subjectParameter [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ] ;
    ars:predicateParameter [ a ars:BlankValue ] ;
    ars:objectParameter [ a ars:BlankValue ] .

n0:inv_set a ars:Invocation ;
    ars:order 0 ;
    ars:perspective set:perspec ;
    ars:subjectParameter [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ] ;
    ars:predicateParameter [ a ars:BlankValue ] ;
    ars:objectParameter [ a ars:BlankValue ] .

# == Selector Attributes ==
#
# What a style's selector says: every statement of the node it is handed, as
# predicate + object rows — one condition a row. One level, and enough: a
# condition's value is a term of the view vocabulary or a number, never a
# node of its own.
#
# A new row starts as a condition rather than as a blank: av:type av:Record,
# the most common thing a selector asks, for the reader to change into the
# one meant — the predicate out of the av: namespace, the value beside it.
# About the node the row is handed, which is what the condition below joins
# on, said again so the row starts there wherever the condition is not the
# one settling it.
#
# It reads everywhere, as the Attributes services do: what is said about this
# node is a question about the node, not about the file it was typed in.

sel:perspec a ars:Perspective ;
    ars:title "Selector Attributes" ;
    ars:description "What a style's selector says, and a new statement started as av:type av:Record." ;
    ars:serviceOf n0:perspec ;
    ars:inFileTabs false ;
    ars:inLensList false ;
    ars:rootDataSource sel:ds_attributes .

sel:ds_attributes a ars:DataSource ;
    ars:predicateVisible true ;
    ars:objectVisible true ;
    ars:loadImportedFiles true ;
    ars:loadUserData true ;
    ars:loadAppDefaults true ;
    ars:adding [
        a ars:RowAction ;
        ars:subjectDefaultValue [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ] ;
        ars:predicateDefaultValue [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "type" ] ;
        ars:objectDefaultValue [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "Record" ] ;
    ] ;
    ars:filter [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
        ars:op ars:eq ;
        ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
    ] .

# == Set Attributes ==
#
# The properties a style sets: every statement of the node it is handed, as
# predicate + object rows — one property a row.
#
# A new row is started in the view vocabulary and left for the reader to
# finish: the predicate is the av: namespace with no name after it, which the
# row's own editor completes out of what that namespace offers, and the value
# an empty text — most properties take a number or a word, and a value that
# is a term is one change of the type cell away.
#
# A click on a value both looks into it and opens its editor
# (ars:objectOnClick ars:expandAndEdit): most values are plain and want
# editing, and the one that is a node of its own — av:content — has a list
# beneath it to look into.
#
# That list is the one subordinate: Content Items, run on the value, and
# enabled only where the invoking row's predicate is av:content
# (ars:enableIf, read in the parent's context as any subordinate's condition
# is) — under a direction, a width or a label role it does not stand at all.

set:perspec a ars:Perspective ;
    ars:title "Set Attributes" ;
    ars:description "The properties a style sets, and a new statement started in the view vocabulary for the reader to finish." ;
    ars:serviceOf n0:perspec ;
    ars:inFileTabs false ;
    ars:inLensList false ;
    ars:rootDataSource set:ds_attributes .

set:ds_attributes a ars:DataSource ;
    ars:predicateVisible true ;
    ars:objectVisible true ;
    ars:objectOnClick ars:expandAndEdit ;
    ars:loadImportedFiles true ;
    ars:loadUserData true ;
    ars:loadAppDefaults true ;
    ars:adding [
        a ars:RowAction ;
        ars:subjectDefaultValue [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ] ;
        ars:predicateDefaultValue [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "" ] ;
        ars:objectDefaultValue [ a ars:LiteralValue ; ars:literal "" ] ;
    ] ;
    ars:filter [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
        ars:op ars:eq ;
        ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
    ] ;
    ars:child set:inv_content .

set:inv_content a ars:Invocation ;
    ars:order 0 ;
    ars:perspective items:perspec ;
    ars:enableIf [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:predicate ; ars:bindingDistance 1 ] ;
        ars:op ars:eq ;
        ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "content" ]
    ] ;
    ars:subjectParameter [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ] ;
    ars:predicateParameter [ a ars:BlankValue ] ;
    ars:objectParameter [ a ars:BlankValue ] .

# == Content Items ==
#
# The items a node holds: its av:item statements and no other — the filter
# pins the predicate beside the join, so the node's own type and order stay
# out of the list — each shown as the item it points at. The value is the
# anonymous node itself, so a click on it looks into it rather than opening
# an editor on a label nobody chose (ars:objectOnClick ars:expand).
#
# In av:order, and movable (ars:sortBy ars:order). The order query says
# where an item's number is: the statement whose subject is the row's
# *object*, the item, where a style's own is about the row's subject — and
# whose predicate is av:order. Pinned like that the number can be written as
# well as found, which is what gives a row its Move up, Move down and Add
# new entry above, and a new item the number after the last. The Add stands
# where the list is a focused rendering, and makes an anonymous node for the
# reader to say more about.
#
# Under each item stands Style Element, with no condition: an item is
# always a node, and what it is — which element, in which role, under what
# number — is what that node states.

items:perspec a ars:Perspective ;
    ars:title "Content Items" ;
    ars:description "The items a content node holds, in av:order and movable, each with what it states beneath it." ;
    ars:serviceOf n0:perspec ;
    ars:inFileTabs false ;
    ars:inLensList false ;
    ars:rootDataSource items:ds_items .

items:ds_items a ars:DataSource ;
    ars:objectVisible true ;
    ars:objectOnClick ars:expand ;
    ars:sortBy ars:order ;
    ars:orderQuery [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "order" ]
        ]
    ] ;
    ars:filter [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:eq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "item" ]
        ]
    ] ;
    ars:child items:inv_attributes .

items:inv_attributes a ars:Invocation ;
    ars:order 0 ;
    ars:perspective elem:perspec ;
    ars:subjectParameter [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ] ;
    ars:predicateParameter [ a ars:BlankValue ] ;
    ars:objectParameter [ a ars:BlankValue ] .

# == Style Element ==
#
# What one content item states: every statement of the node it is handed, as
# predicate + object rows — its element, its role, its name. Every one but
# its av:order: where an item stands is the list's business, kept by Content
# Items' own ordering — moved there, numbered there — and a number shown
# here as well would be a second place to set it, and the one that loses.
# Set Attributes' sibling, and for the same reason a list of its own: an
# item's vocabulary is the view's, a new statement starts there, and the one
# property whose value is a list — a layout's av:content — is read as the
# ordered list it is, by Content Items again.
#
# That is the whole of the recursion: a list of items, each with what it
# states, and under any av:content among that, a list of items. One shape
# of list wherever there is one, so two services that know nothing about
# layouts read a content tree to any depth, in order and movable at every
# level. The ring they make is cut where it comes round, as every ring is —
# a layout's list stands as a stub under its av:content — and opens onward
# from there.
#
# A service of its own rather than Set Attributes run again, so that the
# ring closes a level later: run under a style's own content, Set Attributes
# is already standing above, and an item's statements would be the stub.

elem:perspec a ars:Perspective ;
    ars:title "Style Element" ;
    ars:description "What a content item states, and a new statement started in the view vocabulary for the reader to finish." ;
    ars:serviceOf n0:perspec ;
    ars:inFileTabs false ;
    ars:inLensList false ;
    ars:rootDataSource elem:ds_attributes .

elem:ds_attributes a ars:DataSource ;
    ars:predicateVisible true ;
    ars:objectVisible true ;
    ars:objectOnClick ars:expandAndEdit ;
    ars:loadImportedFiles true ;
    ars:loadUserData true ;
    ars:loadAppDefaults true ;
    ars:adding [
        a ars:RowAction ;
        ars:subjectDefaultValue [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ] ;
        ars:predicateDefaultValue [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "" ] ;
        ars:objectDefaultValue [ a ars:LiteralValue ; ars:literal "" ] ;
    ] ;
    ars:filter [
        a ars:FilterAnd ;
        ars:operand [
            a ars:FilterCompare ; ars:order 0 ;
            ars:left [ a ars:TermValue ; ars:role rdf:subject ] ;
            ars:op ars:eq ;
            ars:value [ a ars:TermValue ; ars:role rdf:subject ; ars:bindingDistance 1 ]
        ], [
            a ars:FilterCompare ; ars:order 1 ;
            ars:left [ a ars:TermValue ; ars:role rdf:predicate ] ;
            ars:op ars:neq ;
            ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "order" ]
        ]
    ] ;
    ars:child elem:inv_content .

elem:inv_content a ars:Invocation ;
    ars:order 0 ;
    ars:perspective items:perspec ;
    ars:enableIf [
        a ars:FilterCompare ;
        ars:left [ a ars:TermValue ; ars:role rdf:predicate ; ars:bindingDistance 1 ] ;
        ars:op ars:eq ;
        ars:value [ a ars:IriValue ; ars:nsUri "https://arspec.org/ars/spec/1/schema/view#" ; ars:localName "content" ]
    ] ;
    ars:subjectParameter [ a ars:TermValue ; ars:role rdf:object ; ars:bindingDistance 1 ] ;
    ars:predicateParameter [ a ars:BlankValue ] ;
    ars:objectParameter [ a ars:BlankValue ] .
