xquery version "1.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 get             = "http://art-decor.org/ns/art-decor-settings" at "art-decor-settings.xqm";
import module namespace art             = "http://art-decor.org/ns/art" at "art-decor.xqm";
import module namespace decor           = "http://art-decor.org/ns/decor" at "../api/api-decor.xqm";
import module namespace hist            = "http://art-decor.org/ns/decor/history" at "../api/api-decor-history.xqm";

let $post               := if (request:exists()) then request:get-data()/valueSetVersions else ()

let $editedValueset     := $post/valueSet
let $decor              := art:getDecorByPrefix($post/@projectPrefix)
let $projectPrefix      := $decor/project/@prefix
let $projectId          := $decor/project/@id
let $locks              := 
    if ($editedValueset[lock]) then 
        decor:getLocks($editedValueset/lock/@ref, $editedValueset/lock/@effectiveDate, (), false())
    else ()
let $currentValueSet     :=
    if (string-length($editedValueset/@originalId)>0)
    then $decor//valueSet[@id=$editedValueset/@originalId][@effectiveDate=$editedValueset/@effectiveDate]
    else $decor//valueSet[@id=$editedValueset/@id][@effectiveDate=$editedValueset/@effectiveDate]
let $userCanEdit        :=
    if ($decor) then decor:authorCanEditP($decor, $decor:SECTION-TERMINOLOGY) else (false())
let $userCanEdit        :=
    if ($locks) then $userCanEdit else if ($currentValueSet) then false() else ($userCanEdit)

let $response           :=
    (:check if user id author in project:)
    if ($userCanEdit) then (
        (:if there is a lock this valueset already exists:)
        if ($locks) then (
            let $baseValueset       :=
                <valueSet>
                {
                    $editedValueset/@id[string-length()>0] |
                    $editedValueset/@name[string-length()>0] |
                    $editedValueset/@displayName[string-length()>0] |
                    $editedValueset/@effectiveDate[string-length()>0] |
                    $editedValueset/@statusCode[string-length()>0] |
                    $editedValueset/@versionLabel[string-length()>0] |
                    $editedValueset/@expirationDate[string-length()>0] |
                    $editedValueset/@officialReleaseDate[string-length()>0] |
                    $editedValueset/@experimental[string-length()>0] |
                    $editedValueset/@canonicalUri[string-length()>0],
                    attribute lastModifiedDate {substring(string(current-dateTime()), 1, 19)}
                }
                </valueSet>
            let $preparedValueSet   := art:prepareValueSetForUpdate($editedValueset, $baseValueset)
            
            let $intention      :=
                if ($currentValueSet[@statusCode='active'][@effectiveDate = $editedValueset/@effectiveDate]) then 'patch' else 'version'
            let $history        :=
                if ($currentValueSet) then 
                    hist:AddHistory($decor:OBJECTTYPE-VALUESET, $editedValueset/@projectPrefix, $intention, $currentValueSet)
                else ()
            let $update             :=
                update replace $currentValueSet with $preparedValueSet
            (: was: update replace $decor//valueSet[@id=$preparedValueSet/@id][@effectiveDate=$preparedValueSet/@effectiveDate] with $preparedValueSet :)
            let $delete             :=
                decor:deleteLock($currentValueSet/@id, $currentValueSet/@effectiveDate, ())
                
            return <data-safe>true</data-safe>
        )
        else (
            (:if a baseId is present use it, else use default baseId:)
            let $valueSetRoot   :=
                if (string-length($editedValueset/@baseId)>0) then
                    $editedValueset/@baseId/string()
                else (
                    decor:getDefaultBaseIds($projectPrefix, $decor:OBJECTTYPE-VALUESET)[1]/@id/string()
                )
            (:get existing valueSet ids, if none return 0:)
            let $maxCurrentId   := max($decor//valueSet[starts-with(@id,$valueSetRoot)]/number(tokenize(@id,'\.')[last()]))+1
            let $maxCurrentId   := if ($maxCurrentId) then $maxCurrentId else (1)

            (:generate new id if mode is 'new' or 'adapt', else use existing id:)
            let $newValueSetId  :=
                if ($editedValueset/edit/@mode=('new','adapt')) then
                    if (count($decor/terminology/valueSet) gt 0) then
                        concat($valueSetRoot, '.', $maxCurrentId)
                    else (concat($valueSetRoot, '.', 1))
                else ($editedValueset/@id)
            let $baseValueset   := 
                <valueSet>
                {
                    attribute id {$newValueSetId} ,
                    $editedValueset/@name[string-length()>0] ,
                    $editedValueset/@displayName[string-length()>0] ,
                    attribute effectiveDate {format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')} ,
                    attribute statusCode {"draft"} ,
                    $editedValueset/@versionLabel[string-length()>0] ,
                    $editedValueset/@expirationDate[string-length()>0] ,
                    $editedValueset/@officialReleaseDate[string-length()>0] ,
                    $editedValueset/@experimental[string-length()>0] ,
                    $editedValueset/@canonicalUri[string-length()>0] ,
                    $editedValueset/@lastModifiedDate[string-length()>0]
                }
                </valueSet>
            let $newValueSet                    := art:prepareValueSetForUpdate($editedValueset, $baseValueset)
            
            let $valueSetAssociation            := 
                if ($editedValueset[string-length(@conceptId)>0]) then 
                    <terminologyAssociation>
                    {
                        $editedValueset/@conceptId,
                        attribute valueSet {$newValueSet/@id},
                        if ($editedValueset[string-length(@flexibility)=0]) then () else (
                            attribute flexibility {$newValueSet/@effectiveDate}
                        ),
                        attribute effectiveDate {format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')}
                    }
                    </terminologyAssociation>
                else ()
            let $terminologyAssociations        :=
                for $concept in $editedValueset//*[string-length(@conceptId)>0][string-length(@code)>0][string-length(@codeSystem)>0]
                return
                    <terminologyAssociation>
                    {
                        $concept/@conceptId, $concept/@code, $concept/@codeSystem, $concept/@displayName, 
                        attribute effectiveDate {format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')}
                    }
                    </terminologyAssociation>
            
            (: prepare sub root elements if not existent :)
            let $valueSetUpdate                 :=
                if (not($decor/terminology) and $decor/codedConcepts) then
                    update insert <terminology/> following $decor/codedConcepts
                else if (not($decor/terminology) and not($decor/codedConcepts)) then
                    update insert <terminology/> following $decor/ids
                else ()
            (: now update the value set :)
            let $valueSetUpdate                 :=
                update insert $newValueSet into $decor/terminology
            
            let $terminologyAssociationUpdates  :=
                art:addTerminologyAssociations($valueSetAssociation | $terminologyAssociations, $decor, false(), false())
            
            return
                <data-safe>true</data-safe>
        )
    )
    else (
        error(QName('http://art-decor.org/ns/art-decor-permissions', 'NoPermission'), concat('You don''t have permission to save this value set. ',get:strCurrentUserName()))
    )

return
    $response
