@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#>.
@prefix owl:   <http://www.w3.org/2002/07/owl#>.
@prefix sh:    <http://www.w3.org/ns/shacl#>.
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#>.
@prefix vcard: <http://www.w3.org/2006/vcard/ns#>.
@prefix :      <#> .

################################## Book

:AddressBookShape a sh:NodeShape;
  sh:targetClass vcard:AddressBook;
  sh:property
    :AddressBook_fn,
    :AddressBook_nameEmailIndex,
    :AddressBook_groupIndex,
    :AddressBook_includesGroup,
    :AddressBook_inAddressBook.

:AddressBook_fn
  sh:path vcard:fn ;
  sh:datatype xsd:string;
  sh:minCount 1;
.

:AddressBook_nameEmailIndex
  sh:path vcard:nameEmailIndex ;
  # sh:datatype xsd:string;
  sh:minCount 1;
.

:AddressBook_groupIndex
  sh:path vcard:groupIndex ;
  a sh:FollowMe; # Loadme before continuing...
  sh:count 1;
.

:AddressBook_includesGroup
  sh:path vcard:includesGroup ;
  sh:mincount 0;
.

:AddressBook_inAddressBook
  sh:path vcard:inAddressBook ; ## Invers
  a sh:FollowMe; # Loadme before continuing...
  sh:count 1;
.


################################## VCARDS

:IndividualShape
  a sh:NodeShape ;
  sh:targetClass vcard:Individual ;
  # sh: targetObjectsOf vcard:member;  # No can be other things
  sh:closed true ; # @@ maybe
  sh:ignoredProperties (owl:sameAs
    <http://www.w3.org/ns/pim/ab#ABPersonFlags>
    <http://www.w3.org/ns/pim/ab#ABDepartment>
    <http://www.w3.org/ns/pim/ab#InstantMessage>
    <http://purl.org/dc/elements/1.1/created>
    <http://purl.org/dc/elements/1.1/modified>);
  sh:property
    :Individual_type,
    :Individual_fn,
    :Individual_hasUID,
    :Individual_hasName,
    :Individual_hasPhoto,
    :Individual_hasRelated,
    :Individual_url,
    :Individual_hasAddress,
    :Individual_anniversary,
    :Individual_hasEmail,
    :Individual_hasTelephone,
    :Individual_organization-name,
    :Individual_role,
    :Individual_title,
    :Individual_note,
    :Individual_inAddressBook.

:Individual_type
    sh:path rdf:type ;
    sh:value vcard:Individual;
    sh:count 1;
.

:Individual_fn
    sh:path vcard:fn ;
    sh:datatype xsd:string;
    sh:pattern ".* .*" ;
    sh:severity sh:Warning ;
    sh:message "Full names without spaces are typically (not always) wrong.";
    sh:maxLength 128;
    sh:minCount 1; # @@ The only thing we insist on
    # sh:maxCount 1;   # For now, alow multiple as the same triple is in many places.
.

:Individual_hasUID
  sh:path vcard:hasUID ;
  sh:maxCount 1;
  sh:minCount 1;
  sh:pattern "^urn:uuid:";
.

:Individual_hasName
  sh:path vcard:hasName ;
  sh:maxCount 1;
.

:Individual_hasPhoto
  sh:path vcard:hasPhoto ;
.

:Individual_hasRelated
  sh:path vcard:hasRelated ;
.

:Individual_url
  sh:path vcard:url ; # @@ Link ot bnode??
.

:Individual_hasAddress
  sh:path vcard:hasAddress ;
.

:Individual_anniversary
  sh:path vcard:anniversary;
  sh:datatype xsd:dateTime; # @@@ Date would be more logical? dateTime in data
  sh:maxCount 1;
.

:Individual_hasEmail
  sh:path vcard:hasEmail ;
.

:Individual_hasTelephone
  sh:path vcard:hasTelephone ;
.

:Individual_organization-name
  sh:path vcard:organization-name;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Individual_role
  sh:path vcard:role;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Individual_title
  sh:path vcard:title;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Individual_note
  sh:path vcard:note;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Individual_inAddressBook
  sh:path vcard:inAddressBook; # Must be the same book
  a sh:BackwardLink;  # Must be stored at least in the book
  sh:maxCount 1;
  sh:minCount 1;
.

####### email

:EmailShape a sh:NodeShape;
  sh:targetObjectsOf vcard:hasEmail;
  sh:property :EmailShape.

:EmailShape
  sh:path vcard:value;
  sh:pattern "^mailto:" ;    # starts with mailto
  sh:count 1;
.

####### phone

:TelephoneShape a sh:NodeShape;
  sh:targetObjectsOf vcard:hasTelephone;
  sh:property :Telephone_hasTelephone.

:Telephone_hasTelephone
  sh:nodeKind sh:IRI;  # what we call NamedNode
  sh:path vcard:value;
  sh:pattern "^tel:" ;    # starts with tel:
  sh:count 1;
.

####### web page

:WebPageShape a sh:NodeShape;
  sh:targetObjectsOf vcard:url;
  sh:property :WebPage_value.

:WebPage_value
   sh:path vcard:value;    # @@ also need to contrail the type part
        sh:pattern "^https?:" ;    # starts with http: or https:
   sh:count 1;
.

######## Structured name

:NameShape a sh:NodeShape;
  sh:targetObjectOf vcard:hasName;
  sh:property
    :Name_family-name,
    :Name_given-name,
    :Name_additional-name,
    :Name_honorific-prefix,
    :Name_honorific-suffix;
  sh:closed true .

:Name_family-name
  sh:path vcard:family-name;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Name_given-name
  sh:path vcard:given-name;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Name_additional-name
  sh:path vcard:additional-name;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Name_honorific-prefix
  sh:path vcard:honorific-prefix;
  sh:datatype xsd:string;
  sh:maxCount 1;
.

:Name_honorific-suffix
  sh:path vcard:honorific-suffix;
  sh:datatype xsd:string;
  sh:maxCount 1;
.


############# groups

:GroupShape a sh:NodeShape;
  sh:targetClass vcard:Group;
  sh:property
    :Group_fn,
    :Group_member.

:Group_fn
  sh:path vcard:fn ;
  sh:datatype xsd:string;
  sh:minCount 1;
.

:Group_member
  sh:path vcard:member;
.

# ends

