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

declare namespace request   = "http://exist-db.org/xquery/request";
declare namespace response  = "http://exist-db.org/xquery/response";
declare namespace hl7       = "urn:hl7-org:v3";

declare %private function local:filterDataset($concept as element(),$representingTemplate as element())  as element()* {
    let $id := $concept/@id
    return
        if (exists($representingTemplate/concept[@ref=$id])) then
            $concept
        else (),
        for $subConcept in $concept/concept
        return
            local:filterDataset($subConcept,$representingTemplate)

};

declare %private function local:scenarioBasics($scenario as element(), $transactionmap as item(), $projectPrefix as xs:string?, $projectLanguage as xs:string?, $oidnamemap as item(), $templatemap as item()) as element() {
    let $iddisplay              := map:get($oidnamemap, $scenario/@id)
    return
        <scenario>
        {
            $scenario/@id,
            $scenario/@effectiveDate,
            $scenario/@statusCode,
            attribute versionLabel {$scenario/@versionLabel},
            attribute expirationDate {$scenario/@expirationDate},
            attribute officialReleaseDate {$scenario/@officialReleaseDate},
            attribute canonicalUri {$scenario/@canonicalUri},
            $scenario/@lastModifiedDate,
            if (string-length($iddisplay) = 0) then () else attribute iddisplay {$iddisplay},
            if ($scenario/ancestor::decor/project[@prefix = $projectPrefix]) then () else (
                attribute ident {$scenario/ancestor::decor/project/@prefix}
            )
            ,
            $scenario/ancestor::decor/@versionDate,
            $scenario/ancestor::decor/@language
            ,
            if (empty($projectLanguage)) then () else
            if ($projectLanguage='*') then () else
            if ($scenario/name[@language = $projectLanguage]) then () else (
                <name language="{$projectLanguage}">{($scenario/name[@language = 'en-US'], $scenario/name)[1]/node()}</name>
            )
            ,
            for $node in $scenario/name
            return
                art:serializeNode($node)
            ,
            for $node in $scenario/desc
            return
                art:serializeNode($node)
            ,
            if ($scenario[desc/@language=$projectLanguage]) then () else (
                <desc language="{$projectLanguage}"/>
            ),
            for $node in $scenario/trigger
            return
                art:serializeNode($node)
            ,
            for $node in $scenario/condition
            return
                art:serializeNode($node)
            ,
            (: new ... 2021-05-21 :)
            for $node in $scenario/publishingAuthority
            return
                <publishingAuthority>
                {
                    $node/@id[not(. = '')],
                    $node/@name[not(. = '')],
                    for $addr in $node/addrLine
                    return
                        art:serializeNode($addr)
                }
                </publishingAuthority>
            ,
            (: new ... 2021-05-21 :)
            for $node in $scenario/property
            return
                art:serializeNode($node)
            ,
            (: new ... 2021-05-21 :)
            for $node in $scenario/copyright
            return
                art:serializeNode($node)
            ,
            for $transaction in $scenario/transaction
            return
                local:transactionBasics($transaction, $projectPrefix, $projectLanguage, $oidnamemap, $templatemap)
        }
        </scenario>
};

declare %private function local:transactionBasics($transaction as element(), $projectPrefix as xs:string?, $projectLanguage as xs:string?, $oidnamemap as item(), $templatemap as item()) as element() {
    let $iddisplay              := map:get($oidnamemap, $transaction/@id)
    return
        (:  transactions got versionable later in time, so may need to patch for content. Assume that it inherits 
            from e.g. scenario if it doesn't have its own data :)
        <transaction>
        {
            $transaction/@id,
            (:DO NOT CREATE HERE. This attribute, if missing gets created in the save-process:)
            $transaction/@effectiveDate,
            $transaction/@statusCode,
            attribute versionLabel {$transaction/@versionLabel},
            $transaction/@expirationDate,
            $transaction/@officialReleaseDate,
            attribute type {$transaction/@type},
            attribute label {$transaction/@label},
            attribute model {$transaction/@model},
            attribute canonicalUri {$transaction/@canonicalUri},
            $transaction/@lastModifiedDate,
            if (string-length($iddisplay) = 0) then () else attribute iddisplay {$iddisplay},
            if ($transaction/ancestor::decor/project[@prefix = $projectPrefix]) then () else (
                attribute ident {$transaction/ancestor::decor/project/@prefix}
            )
            ,
            if (empty($projectLanguage)) then () else
            if ($projectLanguage='*') then () else
            if ($transaction/name[@language=$projectLanguage]) then () else (
                <name language="{$projectLanguage}">{($transaction/name[@language = 'en-US'], $transaction/name)[1]/node()}</name>
            )
            ,
            for $node in $transaction/name
            return
                art:serializeNode($node)
            ,
            for $node in $transaction/desc
            return
                art:serializeNode($node)
            ,
            if (empty($projectLanguage)) then () else
            if ($projectLanguage='*') then () else
            if ($transaction[desc/@language=$projectLanguage]) then () else (
                <desc language="{$projectLanguage}"/>
            ),
            for $node in $transaction/trigger
            return
                art:serializeNode($node)
            ,
            for $node in $transaction/condition
            return
                art:serializeNode($node)
            ,
            for $node in $transaction/dependencies
            return
                art:serializeNode($node)
            ,
            (: new ... 2021-05-21 :)
            for $node in $transaction/publishingAuthority
            return
                <publishingAuthority>
                {
                    $node/@id[not(. = '')],
                    $node/@name[not(. = '')],
                    for $addr in $node/addrLine
                    return
                        art:serializeNode($addr)
                }
                </publishingAuthority>
            ,
            (: new ... 2021-05-21 :)
            for $node in $transaction/property
            return
                art:serializeNode($node)
            ,
            (: new ... 2021-05-21 :)
            for $node in $transaction/copyright
            return
                art:serializeNode($node)
        }
        {
            if ($transaction/@type='group') then (
                for $t in $transaction/transaction
                return
                    local:transactionBasics($t, $projectPrefix, $projectLanguage, $oidnamemap, $templatemap)
            )
            else (
                if ($transaction[actors]) then
                    $transaction/actors
                else (
                    <actors/>
                ),
                if ($transaction[representingTemplate]) then () else (
                    <representingTemplate/>
                )
                ,
                for $representingTemplate in $transaction/representingTemplate
                let $dataset    := 
                    if ($representingTemplate/@sourceDataset) then 
                        art:getDataset($representingTemplate/@sourceDataset, $representingTemplate/@sourceDatasetFlexibility)
                    else ()
                let $template   := 
                    if ($representingTemplate[@ref]) then 
                        map:get($templatemap, concat($representingTemplate/@ref, $representingTemplate/@flexibility[. castable as xs:dateTime]))
                    else ()
                let $questionnaire  :=
                    if ($representingTemplate[@representingQuestionnaire]) then 
                        if ($representingTemplate[@representingQuestionnaireFlexibility castable as xs:dateTime]) then
                            $get:colDecorData//questionnaire[@id = $representingTemplate/@representingQuestionnaire][@effectiveDate = $representingTemplate/@representingQuestionnaireFlexibility]
                        else (
                            let $q := $get:colDecorData//questionnaire[@id = $representingTemplate/@representingQuestionnaire]
                            return
                                $q[@effectiveDate = string(max($q/xs:dateTime(@effectiveDate)))]
                        )
                    else ()
                return
                    <representingTemplate>
                    {
                        $representingTemplate/@sourceDataset,
                        $representingTemplate/@sourceDatasetFlexibility,
                        $representingTemplate/@ref,
                        $representingTemplate/@flexibility,
                        $representingTemplate/@representingQuestionnaire,
                        $representingTemplate/@representingQuestionnaireFlexibility,
                        if ($template) then (
                            attribute templateId {$template/(@id|@ref)},
                            attribute templateDisplayName {($template/@displayName, $template/@name)[not(. = '')][1]},
                            if ($template[@effectiveDate]) then attribute templateEffectiveDate {$template/@effectiveDate} else (),
                            if ($template[@statusCode]) then attribute templateStatusCode {$template/@statusCode} else (),
                            if ($template[@versionLabel]) then attribute templateVersionLabel {$template/@versionLabel} else (),
                            if ($template[@expirationDate]) then attribute templateExpirationDate {$template/@expirationDate} else (),
                            if ($template[@officialReleaseDate]) then attribute templateOfficialReleaseDate {$template/@officialReleaseDate} else (),
                            if ($template[@ident]) then attribute templatePrefix {$template/@ident} else (),
                            if ($template[@url]) then attribute templateUrl {$template/@url} else (),
                            if ($template[@canonicalUri]) then attribute templateCanonicalUri {$template/@canonicalUri} else ()
                        ) else ()
                        ,
                        if ($questionnaire) then (
                            attribute questionnaireDisplayName {($questionnaire/name[not(. = '')])[1]},
                            if ($questionnaire[1][@effectiveDate]) then attribute questionnaireEffectiveDate {$questionnaire[1]/@effectiveDate} else (),
                            if ($questionnaire[1][@statusCode]) then attribute questionnaireStatusCode {$questionnaire[1]/@statusCode} else (),
                            if ($questionnaire[1][@versionLabel]) then attribute questionnaireVersionLabel {$questionnaire[1]/@versionLabel} else (),
                            if ($questionnaire[1][@expirationDate]) then attribute questionnaireExpirationDate {$questionnaire[1]/@expirationDate} else (),
                            if ($questionnaire[1][@officialReleaseDate]) then attribute questionnaireOfficialReleaseDate {$questionnaire[1]/@officialReleaseDate} else (),
                            if ($questionnaire[1][@ident]) then attribute questionnairePrefix {$questionnaire[1]/@ident} else (),
                            if ($questionnaire[1][@url]) then attribute questionnaireUrl {$questionnaire[1]/@url} else (),
                            if ($questionnaire[1][@canonicalUri]) then attribute questionnaireCanonicalUri {$questionnaire[1]/@canonicalUri} else ()
                        ) else ()
                        ,
                        if ($dataset) then (
                            if ($dataset[@effectiveDate]) then attribute sourceDatasetEffectiveDate {$dataset/@effectiveDate} else (),
                            if ($dataset[@statusCode]) then attribute sourceDatasetStatusCode {$dataset/@statusCode} else (),
                            if ($dataset[@versionLabel]) then attribute sourceDatasetVersionLabel {$dataset/@versionLabel} else (),
                            if ($dataset[@expirationDate]) then attribute sourceDatasetExpirationDate {$dataset/@expirationDate} else (),
                            if ($dataset[@officialReleaseDate]) then attribute sourceDatasetOfficialReleaseDate {$dataset/@officialReleaseDate} else (),
                            if ($dataset[@ident]) then attribute sourceDatasetPrefix {$dataset/@ident} else (),
                            if ($dataset[@url]) then attribute sourceDatasetUrl {$dataset/@url} else (),
                            if ($dataset[@canonicalUri]) then attribute sourceDatasetCanonicalUri {$dataset/@canonicalUri} else (),
                            for $node in $dataset/name
                            return
                                <sourceDatasetName>{$node/@*, $node/node()}</sourceDatasetName>
                        ) else ()
                    }
                    </representingTemplate>
            )
        }
        </transaction>
};

let $projectPrefix          := if (request:exists()) then request:get-parameter('project',()) else ('peri20-')
let $decorVersion           := if (request:exists()) then request:get-parameter('decorVersion',())[string-length()>0][1] else ()
let $language               := if (request:exists()) then request:get-parameter('language',())[string-length()>0][1] else ()
(: 2022-07-01 AD30-777 Deactivated selections by dataset because it can cause hurt on the way back. Dataset filtering is now done 
in the frontend based on representingTemplate/@sourceDataset and @sourceDatasetEffectiveDate :)
(:let $datasetId              := if (request:exists()) then request:get-parameter('datasetId', ())[string-length()>0][not(.='*')] else ()
let $datasetEffectiveDate   := if (request:exists()) then request:get-parameter('datasetEffectiveDate', ())[string-length()>0][not(.='*')] else ():)
let $datasetId              := ()
let $datasetEffectiveDate   := ()
let $clearlocks             := if (request:exists()) then request:get-parameter('clearlocks', 'false')='true' else ('false')

let $decor                  := art:getDecorByPrefix($projectPrefix, $decorVersion, $language)

let $clear                  :=
    if ($clearlocks) then (
        let $userlocks  := decor:getLocks((), (), (), true())
        
        for $lock in $userlocks[@type = ('SC', 'TR')][@prefix = $decor/project/@prefix]
        return decor:deleteLock($lock/@ref, $lock/@effectiveDate, ())
    ) else ()

(:let $datasetId              := $decor//dataset[1]/@id
let $datasetEffectiveDate   := $decor//dataset[1]/@effectiveDate:)

let $filteredScenarios      := 
    if (empty($datasetId)) then $decor/scenarios/scenario else (
        art:getScenariosByDataset($datasetId, $datasetEffectiveDate, $decorVersion, $language)
    )
(: only want to offer scenarios from our own project. If someone added a dataset from our project 
    onto his transaction, we would have scenarios from other projects :)
let $filteredScenarios      := $filteredScenarios[ancestor::decor/project[@prefix = $decor/project/@prefix]]
let $transactionmap         :=
    map:merge(
        if (empty($datasetId)) then (
            for $key in distinct-values($filteredScenarios/transaction/concat(@id, @effectiveDate))
            return
                map:entry($key, ())
        )
        else (
            for $key in distinct-values(art:getTransactionsByDataset($datasetId, $datasetEffectiveDate)/ancestor-or-self::transaction[parent::scenario]/concat(@id, @effectiveDate))
            return
                map:entry($key, ())
        )
    )
let $language               := 
    if (empty($language)) 
    then 
        if (empty($projectPrefix)) then
            $filteredScenarios/ancestor::decor/project/@defaultLanguage
        else
            $decor/project/@defaultLanguage
    else $language

(: build map of oid names. is more costly when you do that deep down :)
let $oidnamemap             :=
    map:merge(
        for $oid in ($filteredScenarios/@id | $filteredScenarios//transaction/@id)
        let $grp := $oid
        group by $grp
        return
            map:entry($oid[1], art:getNameForOID($oid[1], $language[1], $oid[1]/ancestor::decor))
    )
(: build map of template attributes. is more costly when you do that deep down :)
let $templatemap            :=
    map:merge(
        for $representingTemplate in $filteredScenarios//representingTemplate[@ref[not(. = '')]]
        let $tmid       := $representingTemplate/@ref
        let $tmed       := $representingTemplate/@flexibility[. castable as xs:dateTime]
        let $tmided     := concat($tmid, $tmed)
        group by $tmided
        return (
            let $tmid           := $representingTemplate[1]/@ref
            let $tmed           := $representingTemplate[1]/@flexibility[. castable as xs:dateTime]
            let $templates      := $get:colDecorCache//template[@id = $tmid] | $get:colDecorData//template[@id = $tmid]
            let $flexibility    := if ($tmed) then $tmed else max($templates/xs:dateTime(@effectiveDate))
            let $templates      := $templates[@effectiveDate = $flexibility]
            let $templates      := if ($templates) then $templates else $decor//template[@ref = $tmid]
            
            return
                map:entry($tmided, <template>{$templates[1]/(@* except (@ident|@url)),
                    if ($templates[1]/ancestor::cacheme) then (
                        attribute ident {$templates[1]/ancestor::cacheme/@bbrident},
                        attribute url {$templates[1]/ancestor::cacheme/@bbrurl}
                    ) else
                    if ($projectPrefix = $templates[1]/ancestor::decor/project/@prefix) then () else (
                        attribute ident {$templates[1]/ancestor::decor/project/@prefix},
                        attribute url {adserver:getServerURLServices()}
                    )
                }</template>)
        )
    )

return
<scenarios projectPrefix="{$projectPrefix}">
    <actors>
    {
        ()(:for $actor in $filteredScenarios/actors/actor
        return
        <actor>
        {
            $actor/@*,
            for $name in $actor/name
            return
                art:serializeNode($name)
            ,
            for $desc in $actor/desc
            return
                art:serializeNode($desc)
        }
        </actor>:)
    }
    </actors>
{
    for $scenario in $filteredScenarios
    order by $scenario/name[1]/lower-case(text()[1])
    return
        local:scenarioBasics($scenario, $transactionmap, $projectPrefix, $language[1], $oidnamemap, $templatemap)
}
</scenarios>
