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

declare variable $art-languages  := art:getArtLanguages();
(: issue mailing :)
(:
import module namespace im ="http://art-decor.org/ns/artxtra" at "/mailsignal-issues.xqm";
:)

declare %private function local:getIssueInfo ($decor as element(), $issue as element()) as element()* {
    let $objectmap  :=
        map:merge( 
            for $o in $issue/object
            let $oid    := $o/@id
            group by $oid
            return map:entry($o[1]/@id, ($o[1]/@type, $o[1]/@effectiveDate[. castable as xs:dateTime])) 
        )
    return
    <wrap>
    {
        for $objectid in map:keys($objectmap)
        let $te             := map:get($objectmap, $objectid)
        let $objectType     := $te[1]
        let $objectEffDate  := $te[2]
        
        (: optimization. if we let it search without being specific, then performance decreases drastically :)
        let $objectContent := 
            if ($objectType = 'VS') then (
                (:get valueset:)
                let $o  := $decor//valueSet[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate][ancestor::terminology]
            ) else
            if ($objectType = 'DE') then (
                (:get data element (dataset concept):)
                let $o  := $decor//concept[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate][ancestor::datasets][not(ancestor::history)]
            ) else 
            if ($objectType = 'TM') then (
                (:get template:)
                let $o  := $decor//template[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate]
            ) else 
            if ($objectType = 'EL') then (
                (:get template element:)
                let $o  := $decor//element[@id = $objectid]
                return $o[ancestor::template]
            ) else 
            if ($objectType = 'TR' and empty($objectEffDate)) then (
                (:get transaction:)
                let $o  := $decor//transaction[@id = $objectid]
                return $o[ancestor::scenarios]
            ) else 
            if ($objectType = 'TR') then (
                (:get transaction:)
                let $o  := $decor//transaction[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate][ancestor::scenarios]
            ) else 
            if ($objectType = 'DS') then (
                (:get dataset:)
                let $o  := $decor//dataset[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate]
            ) else 
            if ($objectType = 'SC') then (
                (:get scenario:)
                let $o  := $decor//scenario[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate]
            ) else 
            if ($objectType = 'IS') then (
                (:get issue:)
                $decor/issues/issue[@id = $objectid]
            ) else 
            if (empty($objectEffDate)) then (
                (:get any -- performance hit!:)
                $decor//*[@id = $objectid][not(ancestor::history | self::object)]
            ) 
            else (
                (:get any -- performance hit!:)
                let $o  := $decor//*[@id = $objectid]
                return $o[@effectiveDate = $objectEffDate][not(ancestor::history | self::object)]
            )
        let $objectContent := $objectContent[1]
        return
            <object id="{$objectid}">
            {
                if (empty($objectEffDate)) then () else attribute effectiveDate {$objectEffDate},
                if (empty($objectType))    then () else attribute type {$objectType},
                if ($objectType = 'DE') then
                    let $concept := $objectContent
                    return
                    <dataset>
                    {
                        $concept/ancestor::dataset/@id,
                        $concept/ancestor::dataset/name
                    }
                    </dataset>
                else (
                    $objectContent/name
                )
            }
            </object>
    }
    {
        for $event in $issue/assignment | $issue/tracking
        order by $event/xs:dateTime(@effectiveDate)
        return $event
    }
    </wrap>
};

let $user               := if (request:exists()) then (request:get-parameter('user',())[1]) else ()
let $user               := 
    if (string-length($user) gt 0) then 
        $user 
    else if (string-length(get:strCurrentUserName()) gt 0) then 
        get:strCurrentUserName() 
    else (
        'guest'
    )
let $comefrom           := if (request:exists()) then (request:get-parameter('comefrom',())) else ()

let $now                := current-dateTime()
let $userLastlogin      := if ($user = 'guest') then () else aduser:getUserLastLoginTime($user)
let $userDisplayName    := if ($user = 'guest') then () else aduser:getUserDisplayName($user)

let $report             := 
<report>
{
(: --------- user id test --------- :)
    <userid>{$user}</userid>,
    <displayName>{if (string-length($userDisplayName)=0) then $user else $userDisplayName}</displayName>
}
{
    <userupdate comefrom="{$comefrom}">
    {
        (: we come from login, add last login record :)
        if ($comefrom='login' and $user != 'guest') then (
            aduser:setUserLastLoginTime($now)
        ) else ()
    }
    </userupdate>
}
{
    (: --------- last login --------- :)
    <lastlogin>{$userLastlogin}</lastlogin>
}
{
    if ($user != 'guest') then
        (: --------- email test --------- :)
        (:
        try {
        if ( mail:send-email($message, 'localhost', ()) ) then
            <email>Sent Message OK :-)</email>
        else
            <email>Could not Send Message :-(</email>
        } catch * {
            <error>Caught error {$err:code}: {$err:description}</error>
        }
        :)
        <email>verified</email>
    else ()
}
{
    if ($user='guest') then () else (
        let $projects   := 
            (:list of decor projects where user is author:)
            for $decor in decor:getDecorProjectsForCurrentUser()
            let $decorProject               := $decor/project
            let $projectId                  := $decorProject/@id
            let $projectPrefix              := $decorProject/@prefix
            let $projectLang                := $decorProject/@defaultLanguage
            (: get author info for this project - note that user guest may lead to multiple authors... :)
            let $author                     := $decorProject/author[@username = $user]
            let $authorId                   := $author/@id
            let $authorUsername             := $user
            let $authorEmail                := $author/@email
            let $lastVersion                := max($decorProject/(release|version)/xs:dateTime(@date))
            let $userSubscriptionSettings   := aduser:getUserDecorSubscriptionSettings($user,$projectPrefix)
            return
            <project prefix="{$projectPrefix}" defaultLanguage="{$projectLang}" authorid="{$authorId}" authorUsername="{$authorUsername}" authoremail="{$authorEmail}" lastVersion="{$lastVersion}">
            {
                art:getLanguageNodes($decorProject/name, $decorProject/name/@language)
            }
            {
                (: --------- community collections --------- :)
                for $c in decor:getDecorCommunity((), $decorProject/@id, true())
                return
                    <community>
                    {
                        $c/@*,
                        for $data in $c/desc
                        return
                            art:serializeNode($data),
                        $c/access
                    }
                    </community>
            }
            {
                for $issue in $decor//issue[not(tracking[last()][@statusCode = ('closed', 'cancelled', 'rejected')])]
                (:let $lastTrackingDate       := max($issue/tracking/xs:dateTime(@effectiveDate)):)
                (:let $lastTracking           := $issue/tracking[@effectiveDate=$lastTrackingDate][1]:)
                let $lastTracking           := $issue/tracking[last()]
                return (
                    (:who created this issue?:)
                    (:let $firstTracking          := $issue/tracking[@effectiveDate=min($issue/tracking/xs:dateTime(@effectiveDate))][1]:)
                    let $firstTracking          := $issue/tracking[1]
                    (:who is this issue currently assigned to?:)
                    (:let $lastAssignment         := $issue/assignment[@effectiveDate=max($issue/assignment/xs:dateTime(@effectiveDate))][1]:)
                    let $lastAssignment         := $issue/assignment[last()]
                    
                    return
                    if ($lastAssignment[@to = $authorId] | $firstTracking/author[@id = $authorId]) then (
                        (:what's the last thing that happened?:)
                        (:let $lastEventDate          := max(($lastAssignment/xs:dateTime(@effectiveDate), $lastTracking/xs:dateTime(@effectiveDate)))
                        let $lastEvent              := $lastAssignment[@effectiveDate=$lastEventDate] | $lastTracking[@effectiveDate=$lastEventDate]
                        let $lastEvent              := $lastEvent[1]:)
                        let $lastEvent              := ($lastAssignment | $lastTracking)[last()]
                        
                        let $lastEventAuthorId      := $lastEvent/author/@id
                        let $lastEventAuthorName    := 
                            if ($decorProject/author[@id=$lastEventAuthorId]) then
                                $decorProject/author[@id=$lastEventAuthorId]/text()
                            else
                                $lastEvent/author/text()
                        
                        let $currentType            := $issue/@type
                        let $currentPriority        := if ($issue/@priority[string-length()>0]) then ($issue/@priority) else ('N')
                        let $currentStatus          := $lastTracking/@statusCode
                        let $currentLabels          := $lastEvent/@labels
                        
                        let $issueAuthorId          := $firstTracking/author/@id
                        let $issueAuthorUserName    := $decorProject/author[@id=$issueAuthorId]/@username
                        let $issueAssignedId        := $lastAssignment/@to
                        let $issueAssignedUserName  := $decorProject/author[@id=$issueAssignedId]/@username
                        let $issueAssignedName      := 
                            if ($decorProject/author[@id=$issueAssignedId]) then
                                $decorProject/author[@id=$issueAssignedId]/text()
                            else
                                $lastAssignment/@name
                                
                        let $userIsSubscribed       := aduser:userHasIssueSubscription($user,$issue/@id)
                        
                        return
                        if ($lastAssignment/@to=$authorId) then
                            <assignedIssue id="{$issue/@id}" 
                                priority="{$currentPriority}" 
                                displayName="{$issue/@displayName}" 
                                type="{$currentType}" 
                                currentStatusCode="{$currentStatus}"
                                currentLabels="{$currentLabels}" 
                                lastDate="{$lastEvent/@effectiveDate}" 
                                lastAuthorId="{$lastEventAuthorId}"
                                lastAuthor="{$lastEventAuthorName}" 
                                lastAssignmentId="{$issueAssignedId}"
                                lastAssignment="{$issueAssignedName}"
                                currentUserIsSubscribed="{$userIsSubscribed}">
                                
                            {   
                                local:getIssueInfo($decor, $issue)/node()
                            }
                            </assignedIssue>
                        else if ($firstTracking/author/@id=$authorId) then
                            <createdIssue id="{$issue/@id}" 
                                priority="{$currentPriority}" 
                                displayName="{$issue/@displayName}" 
                                type="{$currentType}" 
                                currentStatusCode="{$currentStatus}"
                                currentLabels="{$currentLabels}" 
                                lastDate="{$lastEvent/@effectiveDate}" 
                                lastAuthorId="{$lastEventAuthorId}"
                                lastAuthor="{$lastEventAuthorName}" 
                                lastAssignmentId="{$issueAssignedId}"
                                lastAssignment="{$issueAssignedName}"
                                currentUserIsSubscribed="{$userIsSubscribed}">
                            {   
                                local:getIssueInfo($decor, $issue)/node()
                            }
                            </createdIssue>
                        else ()
                    )
                    else ()
                )
            }
            </project>
         return
            for $m in $projects
            let $lang   := $m/@defaultLanguage
            let $n      := if ($m/name[@language=$lang]) then $m/name[@language=$lang] else $m/name[1] 
            order by lower-case($n)
            return $m
    )
}
</report>

return $report