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 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 vs          = "http://art-decor.org/ns/decor/valueset" at "../api/api-decor-valueset.xqm";

declare namespace xs        = "http://www.w3.org/2001/XMLSchema";

let $projectPrefix              := if (request:exists()) then request:get-parameter('prefix',())                        else ()
let $id                         := if (request:exists()) then request:get-parameter('id',())[not(.='')]                 else ()
let $effectiveDate              := if (request:exists()) then request:get-parameter('effectiveDate',())[not(.='')]      else ()
let $conceptListId              := if (request:exists()) then request:get-parameter('conceptListId',())[not(.='')]      else ()
let $breakLock                  := if (request:exists()) then xs:boolean(request:get-parameter('breakLock','false'))    else (false())
let $language                   := if (request:exists()) then request:get-parameter('language',())[not(.='')]           else ()

let $mode                       := if (request:exists()) then request:get-parameter('mode',()) else ('new')

let $decor                      := art:getDecorByPrefix($projectPrefix)
let $language                   := if ($language) then $language else $decor/project/@defaultLanguage/string()
let $datasetConceptList         := if (empty($conceptListId)) then () else $decor//conceptList[@id = $conceptListId][not(ancestor::history)]

(:let $valueset                   := if (empty($id)) then () else (vs:getValueSetById($id,$effectiveDate,$projectPrefix, false())//valueSet[@id][@effectiveDate])[1]:)
(: This prevents prepopulated publishingAuthority which is then saved :)
let $valueset                   := if (empty($id)) then () else ($get:colDecorData//valueSet[@id = $id] | $get:colDecorCache//valueSet[@id = $id])
let $vsed                       := if ($effectiveDate castable as xs:dateTime) then $effectiveDate else max($valueset/xs:dateTime(@effectiveDate))
let $valueset                   := $valueset[@effectiveDate = $vsed][1]

let $lock                       := if ($mode='edit') then decor:setLock($id, $effectiveDate, false()) else (<true/>)

let $response :=
    if ($lock/self::false) then
        <valueSet>{$lock/node()}</valueSet>
    else if (not($mode=('edit','new','version','adapt'))) then
        <valueSet>{'MODE ''',$mode,''' UNSUPPORTED'}</valueSet>
    else (
        let $useBaseId                  := 
            decor:getDefaultBaseIds($projectPrefix, $decor:OBJECTTYPE-VALUESET)[1]/@id/string()
        let $vsname                     :=
            if ($valueset[@name]) then $valueset/@name else substring(art:shortName($datasetConceptList/ancestor::concept[1]/name[1]),1,80)
        let $vsdisplayname              :=
            if ($valueset[@displayName]) then $valueset/@displayName else $datasetConceptList/ancestor::concept[1]/name[1]
        
        return
        <valueSet 
            projectPrefix="{$projectPrefix}" 
            baseId="{$useBaseId}"
            id="{if ($mode=('new','adapt')) then () else ($valueset/@id)}"
            originalId="{if ($mode=('new','adapt')) then () else ($valueset/@id)}"
            name="{$vsname}"
            displayName="{$vsdisplayname}"
            effectiveDate="{if ($mode=('new','version','adapt')) then () else ($valueset/@effectiveDate)}"
            statusCode="{if ($mode='edit') then $valueset/@statusCode else 'new'}"
            versionLabel="{$valueset/@versionLabel}"
            expirationDate="{$valueset/@expirationDate}"
            officialReleaseDate="{$valueset/@officialReleaseDate}"
            canonicalUri="{$valueset/@canonicalUri}">
        {
            if ($datasetConceptList) then (
                attribute conceptId {$datasetConceptList/@id},
                attribute flexibility {}
            )
            else ()
        }
        <edit mode="{$mode}"/>
        {
            $lock/*
        }
        {
            for $sourceCodeSystem in $valueset//@codeSystem
            let $csid := $sourceCodeSystem
            let $csed := $sourceCodeSystem/../@codeSystemVersion
            group by $csid, $csed
            return
                <sourceCodeSystem id="{$sourceCodeSystem}" identifierName="{art:getNameForOID($csid, $language, $decor)}" canonicalUri="{art:getCanonicalUriForOID('CodeSystem', $csid, $csed, $projectPrefix, ())}"/>
        }
        {
            for $desc in $valueset/desc
            return
                art:serializeNode($desc)
        }
        {
            for $lang in $decor/project/name/@language[not(. = $valueset/desc/@language)]
            return
                <desc language="{$lang}"/>
        }
        {
            for $relshp in $valueset/relationship
              return
              <relationship>
              {
                  $relshp/@type
                  ,
                  $relshp/@ref
                  ,
                  $relshp/@flexibility[. castable as xs:dateTime or . = 'dynamic']
              }
              </relationship>
          }
        {
            if ($valueset/publishingAuthority) then $valueset/publishingAuthority else (
                <publishingAuthority id="" name="">
                    <addrLine type=""/>
                </publishingAuthority>
            )
        }
        {
            if ($valueset/endorsingAuthority) then $valueset/endorsingAuthority else (
                <endorsingAuthority id="" name="">
                    <addrLine type=""/>
                </endorsingAuthority>
            )
        }
        {
            if ($valueset/copyright) then $valueset/copyright else (
                <copyright/>
            )
        }
        {
            if ($valueset/revisionHistory) then (
                for $revisionHistory in $valueset/revisionHistory
                return
                <revisionHistory date="{$revisionHistory/@date}" by="{$revisionHistory/@by}">
                {
                    for $desc in $revisionHistory/desc
                    return
                        art:serializeNode($desc)
                }
                </revisionHistory>
            ) else (
                <revisionHistory date="" by="">
                    <desc language="{$language}"/>
                </revisionHistory>
            )
        }
        <conceptList>
        {
            for $completeCodeSystem in $valueset/completeCodeSystem
            return
                <include codeSystem="{$completeCodeSystem/@codeSystem}" codeSystemName="{$completeCodeSystem/@codeSystemName}" codeSystemVersion="{$completeCodeSystem/@codeSystemVersion}" flexibility="{$completeCodeSystem/@flexibility}" type="{$completeCodeSystem/@type[. = 'D']}">
                {
                    for $f in $completeCodeSystem/filter
                    return
                        <filter property="{$f/@property}" op="{$f/@op}" value="{$f/@value}"/>
                }
                </include>
        }
        {
            for $node in $valueset/conceptList/concept | $valueset/conceptList/exception | $valueset/conceptList/include | $valueset/conceptList/exclude | $datasetConceptList/concept
            return
                if ($node[self::include[@ref]]) then (
                    element {$node/name()}
                    {
                        attribute type {$node/@type[. = 'D']},
                        attribute ref {$node/@ref},
                        attribute flexibility {$node/@flexibility},
                        attribute exception {$node/@exception},
                        for $desc in $node/desc
                        return
                            art:serializeNode($desc)
                        ,
                        for $lang in $decor/project/name/@language[not(. = $node/desc/@language)]
                        return
                            <desc language="{$lang}"/>
                    }
                ) else 
                if ($node[self::include[@op] | self::exclude[@op]]) then (
                    element {$node/name()}
                    {
                        attribute type {$node/@type[. = 'D']},
                        attribute op {$node/@op},
                        attribute code {$node/@code},
                        attribute codeSystem {$node/@codeSystem},
                        attribute codeSystemName {$node/@codeSystemName},
                        attribute displayName {$node/@displayName},
                        for $desc in $node/desc
                        return
                            art:serializeNode($desc)
                        ,
                        for $lang in $decor/project/name/@language[not(. = $node/desc/@language)]
                        return
                            <desc language="{$lang}"/>
                    }
                ) else
                if ($node[self::include[empty(@code)][@codeSystem] | self::exclude[empty(@code)][@codeSystem]]) then (
                    element {$node/name()}
                    {
                        attribute type {$node/@type[. = 'D']},
                        attribute codeSystem {$node/@codeSystem},
                        attribute codeSystemName {$node/@codeSystemName},
                        attribute flexibility {$node/@flexibility},
                        for $desc in $node/desc
                        return
                            art:serializeNode($desc)
                        ,
                        for $lang in $decor/project/name/@language[not(. = $node/desc/@language)]
                        return
                            <desc language="{$lang}"/>
                        ,
                        $node/filter
                    }
                )
                else (
                    let $isDatasetConcept   := exists($node[parent::conceptList/@id] | $node[parent::conceptList/@ref])
                    let $elmname            := if ($node[@exception='true'] or name($node) = 'exception') then 'exception' else 'concept'
                    let $level              := if ($node/@level) then $node/@level else (0)
                    let $type               := if ($node/@type) then $node/@type else ('L')
                    let $codeSystem         := if ($node/@codeSystem) then $node/@codeSystem else if ($elmname='exception') then '2.16.840.1.113883.5.1008' else ()
                    let $displayName        := if ($node/@displayName) then $node/@displayName else if ($node/name[@language=$language]) then $node/name[@language=$language] else ($node/name[1])
                    let $ordinal            := if ($node/@ordinal) then $node/@ordinal else ('')
                    
                    (: if for some reason, associations exist on the current conceptList/concept we might as well use these to populate the valueSet proposal :)
                    let $assocs             := if ($isDatasetConcept) then art:getConceptAssociations($node) else ()
                    
                    return
                    if ($assocs) then
                        for $assoc in $assocs
                        return
                        element {$elmname}
                        {
                            attribute code {$assoc/@code},
                            attribute codeSystem {$assoc/@codeSystem},
                            attribute codeSystemName {$assoc/@codeSystemName},
                            attribute codeSystemVersion {$assoc/@codeSystemVersion},
                            attribute displayName {if ($assoc[@displayName]) then $assoc/@displayName else if ($node/name[@language=$language]) then $node/name[@language=$language] else ($node/name[1])},
                            attribute ordinal {$assoc/@ordinal},
                            attribute conceptId {$assoc/@conceptId},
                            attribute level {$level},
                            attribute type {$type},
                            for $desc in $node/designation
                            return
                                art:serializeNode($desc)
                            ,
                            for $desc in $node/desc
                            return
                                art:serializeNode($desc)
                            ,
                            for $lang in $decor/project/name/@language[not(. = $node/desc/@language)]
                            return
                                <desc language="{$lang}"/>
                        }
                    else (
                        element {$elmname}
                        {
                            attribute code {$node/@code},
                            attribute codeSystem {$codeSystem},
                            attribute codeSystemName {$node/@codeSystemName},
                            attribute codeSystemVersion {$node/@codeSystemVersion},
                            attribute displayName {$displayName},
                            attribute ordinal {$ordinal},
                            if ($isDatasetConcept) then attribute conceptId {$node/@id} else (),
                            attribute level {$level},
                            attribute type {$type},
                            for $desc in $node/designation
                            return
                                art:serializeNode($desc)
                            ,
                            for $desc in $node/desc
                            return
                                art:serializeNode($desc)
                            ,
                            for $lang in $decor/project/name/@language[not(. = $node/desc/@language)]
                            return
                                <desc language="{$lang}"/>
                        }
                    )
                )
        }
        </conceptList>
        </valueSet>
    )

return
    <valueSetVersions projectPrefix="{$projectPrefix}">{$response}</valueSetVersions>