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 adserver        = "http://art-decor.org/ns/art-decor-server" at "../api/api-server-settings.xqm";
import module namespace aduser          = "http://art-decor.org/ns/art-decor-users" at "../api/api-user-settings.xqm";
import module namespace gg              = "http://art-decor.org/ns/decor/governancegroups" at "../api/api-decor-governancegroups.xqm";

declare namespace http                  = "http://expath.org/ns/http-client";
declare namespace sm                    = "http://exist-db.org/xquery/securitymanager";
declare namespace xs                    = "http://www.w3.org/2001/XMLSchema";

declare %private function local:getADRAMStatus($decorReferenceURL as xs:string?) as xs:string {
let $requeststatus  := 
    <http:request method="GET" href="{xs:anyURI($decorReferenceURL)}" status-only="true" follow-redirect="false" timeout="5">
        <http:header name="Content-Type" value="text/xml"/>
        <http:header name="Cache-Control" value="no-cache"/>
        <http:header name="Max-Forwards" value="1"/>
    </http:request>
let $requestadram  := 
    <http:request method="GET" href="{xs:anyURI(concat($decorReferenceURL, '/adram.config.xml'))}" status-only="false" follow-redirect="false" timeout="5">
        <http:header name="Content-Type" value="text/xml"/>
        <http:header name="Cache-Control" value="no-cache"/>
        <http:header name="Max-Forwards" value="1"/>
    </http:request>
(: check availablility of reference/@url :)
let $unavailable    := '500'
let $longtimeago    := '1900-01-01T00:00:00'
let $servicestatus  :=
    if (string-length($decorReferenceURL)=0)
    then '500'
    else
        (: get headers -:)
        (:
            <hc:response xmlns:hc="http://expath.org/ns/http-client" status="200" message="OK" spent-millis="314">
                <hc:header name="server" value="nginx"/>
                <hc:header name="date" value="Tue, 08 Oct 2019 06:30:21 GMT"/>
                <hc:header name="content-type" value="text/xml"/>
                <hc:header name="transfer-encoding" value="chunked"/>
                <hc:header name="connection" value="keep-alive"/>
                <hc:header name="x-xquery-cached" value="true"/>
                <hc:body media-type="text/xml"/>
            </hc:response>
            [body]
        :)
        try {
            let $pubDir         := http:send-request($requeststatus)
            let $statusCode     := $pubDir[self::http:response]/@status
            let $adramConfig    := if ($statusCode='200') then (http:send-request($requestadram)) else ()
            let $adramStatus    := $adramConfig[self::http:response]/@status
            let $adramLastTouch := $adramConfig[not(self::http:response)]//@touched
            (:let $adramHeader := exists($response1/httpclient:headers/httpclient:header[@name='X-Powered-By'][@value='ART-DECOR-ADRAM']):)
            (: check wheter adram is configured there, if so get the @touch attribute to find out when the cron job last touched the config :) 
            let $response2      := 
                if ($adramStatus ='200') then (
                    let $adramLastRun := if (empty($adramLastTouch)) then $longtimeago else $adramLastTouch
                    let $timediff     := days-from-duration(current-dateTime() - xs:dateTime($adramLastRun))
                    
                    (: if last touch is more than 2 days ago assume halted :)
                    return if ($timediff <= 2) then 'adram' else 'halted'
                )
                else (
                    (: if adram.config.xml does not exist then assume 'not configured' :)
                )
                
            return if ($statusCode='200') then concat($statusCode, ' ', $response2) else $unavailable
        } catch * { $unavailable }

return $servicestatus
};

let $project            := if (request:exists()) then request:get-parameter('project',())[string-length()>0]         else ()
let $language           := if (request:exists()) then request:get-parameter('language',())[string-length()>0]        else ()
let $projectId          := if (request:exists()) then request:get-parameter('id',())[string-length()>0]              else ()
let $checkADRAM         := if (request:exists()) then request:get-parameter('checkadram','false')[string-length()>0] else ()
let $decor              :=
    if ($project) then
        art:getDecorByPrefix($project)
    else if ($projectId) then
        art:getDecorById($projectId)
    else ()
let $logo               := $decor/project/reference/@logo
(:let $logosrc        := 
    if (empty($logo)) then () else (
        if (starts-with($logo,'http')) then ($logo) else (
            let $coll   := replace(util:collection-name($decorProject),'/db/apps/','')
            let $imgs   := concat($decorProject/@prefix,'logos')
            return
                (\:https://art-decor.org/decor/data/examples/demo1/demo1-logos/:\)
                concat(replace(adserver:getServerURLArt(),'art-decor/',''),$coll,'/',$imgs,'/',$logo)
        )
    ):)

(:XFORMS extras. This is used as prefix for project logos:)
let $projectColl        := replace(util:collection-name($decor),'^.*data/','')

let $decorProject       := $decor/project
let $projectId          := $decorProject/@id
let $ggl                := try { if ($projectId) then gg:getLinkedGovernanceGroups($projectId) else () } catch * {()}
let $updateUserPrefs    := try { aduser:updateProjectPreference($projectId) } catch * {()}
let $inmigration        := doc(concat(util:collection-name($decorProject), '/', $decorProject/@prefix, 'inmigration.xml'))/*

let $isAuthorOrDba      := decor:isActiveAuthorP($decor, get:strCurrentUserName())
let $isAuthorOrDba      := if ($isAuthorOrDba) then $isAuthorOrDba else try { sm:is-dba(get:strCurrentUserName()) } catch * {false()}

return
    if ($decor) then (
        <project 
            id="{$projectId}" 
            prefix="{$decorProject/@prefix}" 
            experimental="{$decorProject/@experimental='true'}"
            defaultLanguage="{$decorProject/@defaultLanguage}" 
            repository="{$decor/@repository='true'}"
            private="{$decor/@private='true'}"
            lastmodified="{xmldb:last-modified(util:collection-name($decorProject), concat($decorProject/@prefix, 'decor.xml'))}">
        {
            attribute collection {$projectColl},
            (:ADRAM extras:)
            if ($checkADRAM='true' and $decorProject/reference/@url[string-length()>0]) then (
                attribute servicestatus {local:getADRAMStatus($decorProject/reference/@url)}
            ) else ()
        }
        {
            $decorProject/name,
            art:serializeDescriptionNodes($decorProject/desc, $decorProject/name/@language),
            for $copyright in $decorProject/copyright
            let $copyrightType  := if ($copyright[@type]) then $copyright/@type else 'author'
            return
                <copyright by="{$copyright/@by}" logo="{$copyright/@logo}" years="{$copyright/@years}" type="{$copyrightType}">
                {
                    for $node in $copyright/addrLine
                    return
                        <addrLine>{$node/@*[string-length() gt 0], if ($node[@type]) then () else (attribute type {''}), $node/node()}</addrLine>
                }
                </copyright>
            ,
            $decorProject/license,
            for $author in $decorProject/author
            let $active     :=
                if ($author[@expirationDate castable as xs:dateTime][xs:dateTime(@expirationDate) le current-dateTime()]) then false() else (
                    not($author/@active = 'false')
                )
            let $dbactive   :=
                try {
                    if (sm:user-exists($author/@username)) then sm:is-account-enabled($author/@username) else false()
                } 
                catch * {true()}
            return
                if ($isAuthorOrDba or ($active and $dbactive)) then 
                    <author>
                    {
                        $author/@id
                        ,
                        (: mind the GDPR law, see https://art-decor.atlassian.net/browse/AD30-762 :)
                        if ($isAuthorOrDba) then (
                            $author/@username,
                            attribute email {$author/@email},
                            attribute notifier {if ($author/@notifier = ('on', 'true')) then 'on' else 'off'}
                            ,
                            (: is the user active as author? :)
                            attribute active {$active},
                            (: does the user have an active eXist-db account? :)
                            attribute dbactive {$dbactive}
                            ,
                            $author/(@* except (@id|@username|@email|@active|@dbactive|@notifier))
                        ) else ()
                        ,
                        $author/node()
                    }
                    </author>
                else ()
        }
        {
            <reference url="{$decorProject/reference/@url}" logo="{$logo}">
            {()(:if ($logosrc) then attribute logosrc {$logosrc} else ():)}
            </reference>
            ,
            $decorProject/restURI,
            if ($decorProject[defaultElementNamespace]) then 
                $decorProject/defaultElementNamespace
            else (
                <defaultElementNamespace ns="hl7:"/>
            )
            ,
            $decorProject/contact,
            for $bbr in $decorProject/buildingBlockRepository
            return
                <buildingBlockRepository>
                {
                    $bbr/@*,
                    if ($bbr[@format]) then () else (attribute format {'decor'}),
                    $bbr/node()
                }
                </buildingBlockRepository>
            ,
            for $gg in $ggl/partOf/@ref
            return <group id="{$gg}"/>
            (:for $ggl in $get:colDecorData/governance-group-links[@ref = $projectId], $gg in $ggl/partOf/@ref
            return <group id="{$gg}"/>:)
            ,
            art:getDecorNamespaces($decor)
        }
            <ids>
            {
                (:
                Add empty designation for language, otherwise you cannot edit the designation in the project form. TODO: fix empty designations before/on save 
                <id root="1.0.639.2">
                    <designation language="nl-NL" type="" displayName="ISO-639-2 Alpha 3" lastTranslated="" mimeType="">ISO-639-2 Alpha 3 Language</designation>
                </id>
                :)
                (:
                    Old style:
                        <baseId id="1.2.3" type="DS" prefix="xyz"/>
                        <defaultBaseId id="1.2.3" type="DS"/>
                    New style:
                        <baseId id="1.2.3" type="DS" prefix="xyz" default="true"/>
                        
                    Rewrite old style to new style.
                :)
                for $baseId in $decor/ids/baseId
                return
                    <baseId>
                    {
                        $baseId/@*[string-length() gt 0]
                        ,
                        if ($baseId[@default]) then () else (
                            attribute default {$decor//defaultBaseId/@id = $baseId/@id}
                        )
                    }
                    </baseId>
                ,
                (: For now: keep old style so we can fix all dependent code later :)
                $decor/ids/defaultBaseId,
                for $identifier in $decor/ids/id
                return
                    element {name($identifier)} {
                        $identifier/@*,
                        (:create if not available in the language so the user may fill it out:)
                        if (string-length($language)>0 and not($identifier/designation[@language=$language]))
                        then (<designation language="{$language}" type="preferred" displayName=""/>)
                        else (),
                        (:retain anything that was not requested but still in there:)
                        for $designation in $identifier/designation
                        return
                        <designation language="{$designation/@language}" type="{$designation/@type}" displayName="{$designation/@displayName}">
                        {$designation/node()}
                        </designation>
                    }
            }
            </ids>
            <inmigration>
            {
                if (count($inmigration[@type]) > 0) then
                    for $ia in $inmigration/@*
                    return attribute { name($ia) } { $ia }
                else ()
            }
            </inmigration>
            {
                $decor/issues/labels
            }
        </project>
    ) else (
        <project/>
    )