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.
:)

(:
   Xquery for retrieving the concept for read-only purposes.
   Requires id  and effectiveDate as request parameters
   Returns the concept without subconcepts, inherit is resolved, textWithMarkup is serialized.

:)
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";
declare namespace request   = "http://exist-db.org/xquery/request";

let $id             := if (request:exists()) then request:get-parameter('id',()) else ('2.16.840.1.113883.2.4.3.11.60.107.2.1.14544')
let $effectiveDate  := if (request:exists()) then request:get-parameter('effectiveDate',()) else ('2016-07-13T09:07:42')
let $language       := if (request:exists()) then request:get-parameter('language',())[string-length()>0] else ()
let $concept        := art:getConcept($id, $effectiveDate)
let $projectPrefix  := $concept/ancestor::decor/project/@prefix
let $projectId      := $concept/ancestor::decor/project/@id
let $language       := if (empty($language)) then ($concept/ancestor::decor/project/@defaultLanguage)[1] else ($language)[1]

let $username       := get:strCurrentUserName()

let $iddisplay      := art:getNameForOID($id, $concept/ancestor::decor/project/@defaultLanguage, $concept/ancestor::decor)

(:  usually you contain/inherit from the original, but if you contain/inherit from something that inherits, then these two will differ
    originalConcept has the type and the associations. The rest comes from the inheritConcept/containConcept :)
let $inheritConcept   := if ($concept[inherit]) then art:getConcept($concept/inherit/@ref, $concept/inherit/@effectiveDate) else ()
let $containConcept   := if ($concept[contains]) then art:getConcept($concept/contains/@ref, $concept/contains/@flexibility) else ()
let $originalConcept  := art:getOriginalForConcept($concept)

let $communityInfo    := 
    if ($projectId) then (
        decor:getDecorCommunity((), $projectId, (), true())//association[object[concat(@ref, @flexibility) = (concat($id, $concept/@effectiveDate), $originalConcept/concat(@id, @effectiveDate))][@type='DE']]
    ) else ()

return
    if ($concept) then (
        <concept id="{$id}" iddisplay="{$iddisplay}" statusCode="{$concept/@statusCode}" effectiveDate="{$concept/@effectiveDate}" 
                 type="{$originalConcept/@type}" expirationDate="{$concept/@expirationDate}" 
                 officialReleaseDate="{$concept/@officialReleaseDate}" versionLabel="{$concept/@versionLabel}" canonicalUri="{$concept/@canonicalUri}">
        {
            $concept/@lastModifiedDate
        }
        {
            if ($concept[inherit]) then
                <inherit>
                {
                    $concept/inherit/(@ref|@effectiveDate),
                    $inheritConcept/ancestor::decor/project/@prefix,
                    attribute datasetId {$inheritConcept/ancestor::dataset/@id},
                    attribute datasetEffectiveDate {$inheritConcept/ancestor::dataset/@effectiveDate},
                    attribute iType {$originalConcept/@type}, 
                    attribute iStatusCode {$inheritConcept/@statusCode}, 
                    attribute iEffectiveDate {$inheritConcept/@effectiveDate},
                    if ($inheritConcept[@expirationDate]) then attribute iExpirationDate {$inheritConcept/@expirationDate} else (),
                    if ($inheritConcept[@versionLabel]) then attribute iVersionLabel {$inheritConcept/@versionLabel} else (),
                    attribute iddisplay {art:getNameForOID($concept/inherit/@ref, $concept/ancestor::decor/project/@defaultLanguage, $inheritConcept/ancestor::decor)}, 
                    if ($inheritConcept[@id = $originalConcept/@id][@effectiveDate = $originalConcept/@effectiveDate]) then () else (
                        attribute originalId {$originalConcept/@id}, 
                        attribute originalEffectiveDate {$originalConcept/@effectiveDate}, 
                        attribute originalStatusCode {$originalConcept/@statusCode}, 
                        if ($originalConcept[@expirationDate]) then attribute originalExpirationDate {$originalConcept/@expirationDate} else (),
                        if ($originalConcept[@versionLabel]) then attribute originalVersionLabel {$originalConcept/@versionLabel} else (),
                        attribute originalPrefix {$originalConcept/ancestor::decor/project/@prefix}
                    )
                }
                </inherit>
            else ()
        }
        {
            if ($concept[contains]) then
                <contains>
                {
                    $concept/contains/@ref, $concept/contains/@flexibility,
                    $containConcept/ancestor::decor/project/@prefix,
                    attribute datasetId {$containConcept/ancestor::dataset/@id},
                    attribute datasetEffectiveDate {$containConcept/ancestor::dataset/@effectiveDate},
                    attribute iType {$originalConcept/@type}, 
                    attribute iStatusCode {$containConcept/@statusCode}, 
                    attribute iEffectiveDate {$containConcept/@effectiveDate},
                    if ($containConcept[@expirationDate]) then attribute iExpirationDate {$containConcept/@expirationDate} else (),
                    if ($containConcept[@versionLabel]) then attribute iVersionLabel {$containConcept/@versionLabel} else (),
                    attribute iddisplay {art:getNameForOID($concept/contains/@ref, $concept/ancestor::decor/project/@defaultLanguage, $containConcept/ancestor::decor)},
                    if ($containConcept[@id = $originalConcept/@id][@effectiveDate = $originalConcept/@effectiveDate]) then () else (
                        attribute originalId {$originalConcept/@id}, 
                        attribute originalEffectiveDate {$originalConcept/@effectiveDate}, 
                        attribute originalStatusCode {$originalConcept/@statusCode}, 
                        if ($originalConcept[@expirationDate]) then attribute originalExpirationDate {$originalConcept/@expirationDate} else (),
                        if ($originalConcept[@versionLabel]) then attribute originalVersionLabel {$originalConcept/@versionLabel} else (),
                        attribute originalPrefix {$originalConcept/ancestor::decor/project/@prefix}
                    )
                }
                </contains>
            else 
            if ($inheritConcept[contains]) then (
                let $containedConcept   := art:getOriginalForConcept($inheritConcept)
                return
                <contains>
                {
                    $inheritConcept/contains/@ref, $inheritConcept/contains/@flexibility,
                    $containedConcept/ancestor::decor/project/@prefix,
                    attribute datasetId {$containedConcept/ancestor::dataset/@id},
                    attribute datasetEffectiveDate {$containedConcept/ancestor::dataset/@effectiveDate},
                    attribute iType {$containedConcept/@type}, 
                    attribute iStatusCode {$containedConcept/@statusCode}, 
                    attribute iEffectiveDate {$containedConcept/@effectiveDate},
                    if ($containedConcept[@expirationDate]) then attribute iExpirationDate {$containedConcept/@expirationDate} else (),
                    if ($containedConcept[@versionLabel]) then attribute iVersionLabel {$containedConcept/@versionLabel} else (),
                    attribute iddisplay {art:getNameForOID($inheritConcept/contains/@ref, $concept/ancestor::decor/project/@defaultLanguage, $containedConcept/ancestor::decor)}
                }
                </contains>
            )
            else ()
        }
        {
            for $name in $originalConcept/name
            return
            art:serializeNode($name)
            ,
            for $synonym in $originalConcept/synonym
            return
            art:serializeNode($synonym)
            ,
            for $desc in $originalConcept/desc
            return
            art:serializeNode($desc)
            ,
            for $source in $originalConcept/source
            return
            art:serializeNode($source)
            ,
            for $rationale in $originalConcept/rationale
            return
            art:serializeNode($rationale)
            ,
            if ($concept[inherit | contains]) then 
                for $comment in $originalConcept/comment
                return
                <inheritedComment language="{$comment/@language}">{art:serializeNode($comment)/text()}</inheritedComment>
            else ()
            ,
            for $comment in $concept/comment
            return
            art:serializeNode($comment)
            ,
            (:new since 2015-04-21:)
            for $property in $originalConcept/property
            return
            art:serializeNode($property)
            ,
            (:new since 2015-04-21:)
            for $relationship in $originalConcept/relationship
            let $referredConcept            := art:getConcept($relationship/@ref, $relationship/@flexibility)
            let $originalReferredConcept    := art:getOriginalForConcept($referredConcept)[1]
            return
                <relationship type="{$relationship/@type}" ref="{$relationship/@ref}" flexibility="{$relationship/@flexibility}">
                {
                    $referredConcept/ancestor::decor/project/@prefix,
                    attribute datasetId {$referredConcept/ancestor::dataset/@id},
                    attribute datasetEffectiveDate {$referredConcept/ancestor::dataset/@effectiveDate},
                    attribute iType {$originalReferredConcept/@type}, 
                    attribute iStatusCode {$referredConcept/@statusCode}, 
                    if ($referredConcept[@expirationDate]) then attribute iExpirationDate {$referredConcept/@expirationDate} else (),
                    if ($referredConcept[@versionLabel]) then attribute iVersionLabel {$referredConcept/@versionLabel} else (),
                    attribute iddisplay {art:getNameForOID($relationship/@ref, $language, $referredConcept/ancestor::decor)},
                    attribute localInherit {$referredConcept/ancestor::decor/project/@prefix = $projectPrefix},
                    $originalReferredConcept/name,
                    if ($originalReferredConcept/name[@language=$language]) then () else (
                        <name language="{$language}">{data($originalReferredConcept/name[1])}</name>
                    )
                }
                </relationship>
            ,
            for $operationalization in $originalConcept/operationalization
            return
            art:serializeNode($operationalization)
            ,
            for $valueDomain in $originalConcept/valueDomain
            return
                <valueDomain>
                {
                    $valueDomain/@*,
                    $valueDomain/property[@*[string-length()>0]],
                    for $conceptList in $valueDomain/conceptList 
                    let $originalConceptList := art:getOriginalConceptList($conceptList)
                    return
                        <conceptList>
                        {
                            (:note that this will retain conceptList[@ref] if applicable:)
                            $conceptList/(@* except @conceptId),
                            if ($conceptList[@ref]) then (
                                attribute prefix {$originalConceptList/ancestor::decor/project/@prefix},
                                attribute conceptId {$originalConceptList/ancestor::concept[1]/@id},
                                attribute conceptEffectiveDate {$originalConceptList/ancestor::concept[1]/@effectiveDate},
                                attribute datasetId {$originalConceptList/ancestor::dataset[1]/@id},
                                attribute datasetEffectiveDate {$originalConceptList/ancestor::dataset[1]/@effectiveDate}
                            )
                            else (),
                            for $conceptListNode in $originalConceptList/*
                            return
                                if ($conceptListNode/self::concept) then (
                                    <concept>
                                    {
                                        $conceptListNode/@*,
                                        $conceptListNode/name,
                                        $conceptListNode/synonym,
                                        for $node in $conceptListNode/desc
                                        return art:serializeNode($node)
                                    }
                                    </concept>
                                )
                                else (
                                    $conceptListNode
                                )
                        }
                        </conceptList>
                    ,
                    $valueDomain/example
                }
                </valueDomain>
            ,
            for $associations in $communityInfo
            let $communityPrefix := $associations/ancestor::community/@name
            group by $communityPrefix
            return
                <community name="{$communityPrefix}">
                {
                    $associations[1]/ancestor::community/@displayName,
                    $associations[1]/ancestor::community/desc,
                    <prototype>
                    {
                        let $prototypes     :=
                            if ($associations[1]/ancestor::community/prototype/@ref) then 
                                doc(xs:anyURI($associations[1]/ancestor::community/prototype/@ref))/prototype
                            else
                                $associations[1]/ancestor::community/prototype
                        
                        return $prototypes/data[@type = $associations//data/@type]
                    }
                    </prototype>,
                    <associations>
                    {
                        for $association in $associations
                        return
                            <association>
                            {
                                $association/@*,
                                for $data in $association/data
                                return
                                art:serializeNode($data)
                            }
                            </association>
                    }
                    </associations>
                }
                </community>
            ,
            $concept/history
        }
        </concept>
    )
    else (
        (:response:set-status-code(404):)
    )

