xquery version "3.0";
(:
    ART-DECOR® STANDARD COPYRIGHT AND LICENSE NOTE
    Copyright © ART-DECOR Expert Group and ART-DECOR Open Tools GmbH
    see https://docs.art-decor.org/copyright and https://docs.art-decor.org/licenses

    This file is part of the ART-DECOR® tools suite.
:)
import module namespace art     = "http://art-decor.org/ns/art" at "art-decor.xqm";
import module namespace get     = "http://art-decor.org/ns/art-decor-settings" at "art-decor-settings.xqm";
declare namespace error         = "http://art-decor.org/ns/decor/terminology/error";

(: function will return only the first of potentially multiple matches :)
declare %private function local:getIdentifierAssociation($associations as element(identifierAssociation)+, $s_ref as xs:string?, $s_effectiveDate as xs:string?, $s_statusCode as xs:string?) as element() {
    (:filter on effectiveDate:)
    let $associations           := if (empty($s_effectiveDate)) then ($associations) else ($associations[@effectiveDate = $s_effectiveDate])
    
    (:filter on statusCode:)
    let $associations           := if (empty($s_statusCode)) then ($associations) else ($associations[@statusCode = $s_statusCode])
    
    (:filter on ref:)
    let $associations           := if (empty($s_ref)) then ($associations) else ($associations[@ref = $s_ref])
    
    return
        $associations[1]
};

let $updatedAssociation     := if (request:exists()) then request:get-data()/updatedAssociation else (
    (:<updatedAssociation conceptId="" effectiveDate="" statusCode="removed" versionLabel="" expirationDate="" actionText="Koppeling verwijderen" prefix="demo1-" parentConceptId="2.16.840.1.113883.3.1937.99.62.3.2.7" parentConceptFlexibility="2012-05-30T14:18:23">
        <identifierAssociation conceptId="2.16.840.1.113883.3.1937.99.62.3.2.7" conceptFlexibility="2012-05-30T14:18:23" ref="2.16.528.1.1007.3.1" effectiveDate="2018-08-25T20:52:40" equivalence="" refdisplay="UZI nummer natuurlijke personen; zorgverlener of medewerker met UZI pas"/>
    </updatedAssociation>:)
)

let $projectPrefix              := $updatedAssociation/@prefix[string-length() gt 0]
let $transactionId              := $updatedAssociation/*[1]/@transactionId[string-length() gt 0]
let $transactionEffectiveDate   := $updatedAssociation/*[1]/@transactionEffectiveDate[string-length() gt 0]

let $s_cid                      := $updatedAssociation/*[1]/@conceptId[string-length() gt 0]
let $s_ced                      := $updatedAssociation/*[1]/@conceptFlexibility[string-length() gt 0]

(: relevant for transaction bindings to conceptList/concept to know which concept to add them to :)
let $conceptId                  := if ($updatedAssociation/@parentConceptId[string-length() gt 0]) then $updatedAssociation/@parentConceptId else $s_cid
let $conceptEffectiveDate       := if ($updatedAssociation/@parentConceptFlexibility[string-length() gt 0]) then $updatedAssociation/@parentConceptFlexibility else $s_ced

let $s_ref                      := $updatedAssociation/*[1]/@ref[string-length() gt 0]
let $s_effectiveDate            := $updatedAssociation/*[1]/@effectiveDate[string-length() gt 0]
let $s_statusCode               := $updatedAssociation/*[1]/@statusCode[string-length() gt 0]
let $s_versionLabel             := $updatedAssociation/*[1]/@versionLabel[string-length() gt 0]

(: 
    the only 'statusCode' we currently will support is 'removed'. This is not an actual statusCode, 
    but an instruction to delete the terminologyAssociation
    It's very well possible that in some future stage, terminologyAssociations will have a statusCode.
:)
let $u_statusCode               := $updatedAssociation/@statusCode[. = 'removed']
let $u_versionLabel             := $updatedAssociation/@versionLabel[string-length() gt 0]
let $u_expirationDate           := 
    if ($updatedAssociation/@expirationDate castable as xs:date) then
        concat($updatedAssociation/@expirationDate,'T00:00:00')
    else if ($updatedAssociation/@expirationDate castable as xs:dateTime) then
        $updatedAssociation/@expirationDate
    else ()

let $now                        := format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')

let $associations               :=
    if ($transactionId) then
        art:getTransactionConcept($conceptId, $conceptEffectiveDate, $transactionId, $transactionEffectiveDate, (), ())/identifierAssociation
    else (
        art:getDecorByPrefix($projectPrefix)/ids/identifierAssociation
    )
let $associations               := 
    if ($s_ced castable as xs:dateTime) then 
        $associations[@conceptId = $s_cid][@conceptFlexibility = $s_ced] 
    else (
        $associations[@conceptId = $s_cid]
    )

(: function will purposely error when no match or more than one match is found :)
let $currentAssociation         := local:getIdentifierAssociation($associations, $s_ref, $s_effectiveDate, ())

let $result                     :=
    if ($u_statusCode='removed') then
        update delete $currentAssociation
    else (
        (:if ($u_statusCode) then
            if ($currentAssociation[@statusCode]) then
                update value $currentAssociation/@statusCode with $u_statusCode
            else (
                update insert attribute statusCode {$u_statusCode} into $currentAssociation
            )
        else (
            update delete $currentAssociation/@statusCode
        )
        ,:)
        if ($u_versionLabel) then 
            if ($currentAssociation[@versionLabel]) then
                update value $currentAssociation/@versionLabel with $u_versionLabel
            else (
                update insert attribute versionLabel {$u_versionLabel} into $currentAssociation
            )
        else (
            update delete $currentAssociation/@versionLabel
        )
        ,
        if ($u_expirationDate) then 
            if ($currentAssociation[@expirationDate]) then
                update value $currentAssociation/@expirationDate with $u_expirationDate
            else (
                update insert attribute expirationDate {$u_expirationDate} into $currentAssociation
            )
        else if ($u_statusCode = 'retired') then
            if ($currentAssociation[@expirationDate]) then
                update value $currentAssociation/@expirationDate with $now
            else (
                update insert attribute expirationDate {$now} into $currentAssociation
            )
        else (
            update delete $currentAssociation/@expirationDate
        )
    )

return
    <data-safe>{true()}</data-safe>