xquery version "3.1";

(:
 : This module handles calls to the API on collection level, e.g.
 :
 : /textapi/ahiqar/3r9ps/collection.json
 :)

module namespace tapi-coll="http://ahiqar.uni-goettingen.de/ns/tapi/collection";

declare namespace ore="http://www.openarchives.org/ore/terms/";
declare namespace rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace tgmd="http://textgrid.info/namespaces/metadata/core/2010";

import module namespace commons="http://ahiqar.uni-goettingen.de/ns/commons" at "commons.xqm";
import module namespace tapi-mani="http://ahiqar.uni-goettingen.de/ns/tapi/manifest" at "tapi-manifest.xqm";

declare variable $tapi-coll:uris :=
    map {
        "syriac":
            if (doc-available($commons:agg || "3r84g.xml"))
            then "3r84g"
            else
                let $log := util:log("warning", "falling back to sample collection. This might be a hint to an incomplete import process.")
            return "sample_lang_aggregation_syriac",
        "arabic": (
            if (doc-available($commons:agg || "3r9ps.xml"))
            then "3r9ps"
            else
                let $log := util:log("warning", "falling back to sample collection. This might be a hint to an incomplete import process.")
            return "sample_lang_aggregation_arabic"
            ),
        "karshuni": (
            if (doc-available($commons:agg || "3r84h.xml"))
            then "3r84h"
            else
                let $log := util:log("warning", "falling back to sample collection. This might be a hint to an incomplete import process.")
            return "sample_lang_aggregation_karshuni"),
        "neo-aramaic": (
            if (doc-available($commons:agg || "40xnp.xml")) then
                "40xnp"
            else
                ()
        ),
         "sogdian": (
            if (doc-available($commons:agg || "41np5.xml")) then
                "41np5"
            else
                ()
        )
    };

declare function tapi-coll:get-uris($collection-type as xs:string)
as xs:string+ {
    map:get($tapi-coll:uris, $collection-type)
};


(:~
 : Returns information about the main collection for the project. This encompasses
 : the key data described at https://subugoe.pages.gwdg.de/emo/text-api/page/specs/#collection-object.
 :
 : This function should only be used for Ahiqar's edition object (textgrid:3r132).
 : It serves as an entry point to the edition and contains all child aggregations with
 : the XMLs and images in them.
 :
 : @see https://subugoe.pages.gwdg.de/emo/text-api/page/specs/#collection-object
 : @param $collection-type The collection type as defined in `commons:validate-rest-input`
 : @return An object element containing all necessary information
 :)
declare function tapi-coll:get-json($collection-type as xs:string)
as map() {
    let $collector-birol := map {
        "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/actor.jsonld",
        "name": "Birol, Simon",
        "role": array {"collector"},
        "idref": array {
            map {
                "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/idref.jsonld",
                "base": "http://d-nb.info/gnd/",
                "id": "1150408537",
                "type": "GND"
            }
        }
    }
    let $collector-elrefaei := map {
        "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/actor.jsonld",
        "name": "Dr. Elrefaei, Aly",
        "role": array {"collector"},
        "idref": array {
            map {
                "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/idref.jsonld",
                "base": "http://d-nb.info/gnd/",
                "id": "1081516585",
                "type": "GND"
            }
        }
    }
    let $lang-for-title :=
        if (contains($collection-type, "syriac")) then
            "Syriac"
        else if (contains($collection-type, "arabic")) then
            "Arabic"
        else if (contains($collection-type, "karshuni")) then
            "Karshuni"
        else if (contains($collection-type, "neo")) then
            "Neo-Aramaic"
        else if (contains($collection-type, "sogdian")) then
            "Sogdian"
        else
            "Unknown Collection"
    return
        map {
            "textapi": $commons:textapi-version,
            "x-app-version": $commons:version,
            "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/collection.jsonld",
            "id": $commons:server || "/" || $commons:api-prefix || $collection-type || "/collection.json",
            "title": array {
                map {
                    "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/title.jsonld",
                    "title": concat("Textual witnesses in ", $lang-for-title),
                    "type": "main"
                }
            },
            "collector": array {
                if (contains($collection-type, "arabic")
                or contains($collection-type, "karshuni")) then
                    $collector-elrefaei
                else
                    $collector-birol
            },
            "annotationCollection": tapi-coll:make-annotationCollection-uri($collection-type),
            "description": concat(tapi-coll:get-collection-string($collection-type), " collection for the Ahiqar project. Funded by DFG, 2018–2025, University of Göttingen"),
            "sequence": array { tapi-coll:make-sequence($collection-type) }
        }
};

declare function tapi-coll:get-collection-string($collection-type as xs:string)
as xs:string {
    switch ($collection-type)
        case "syriac" return "Syriac"
        case "arabic" return "Arabic"
        case "karshuni" return "Karshuni"
        case "neo-aramaic" return "Neo-Aramaic"
        case "sogdian" return "Sogdian"
        default return error(QName($commons:ns, "COLLECTION01"), "Unknown collection type " || $collection-type)
};


declare function tapi-coll:get-aggregations($uris as xs:string+)
as document-node()+ {
    for $uri in $uris return
        doc($commons:agg || $uri || ".xml")
};


(:~
 : Some "editions" that appear in the ore:aggregates list of a collection are
 : actually no editions; They lack an XML file.
 :
 : In order to not have them included in the list of "actual" editions, they
 : have to be explicitly excluded.
 :
 : @param $aggregatins The root element(s) of one or more aggregation objects
 : @return A list of ore:aggregates without the manifests to be excluded
 :
 :)
declare function tapi-coll:get-allowed-manifest-uris($aggregations as node()+)
as xs:string+ {
    let $not-allowed :=
        (
            "textgrid:3vp38"
        )
    let $allowed :=
        for $aggregation-file in $aggregations return
            for $aggregate in $aggregation-file//ore:aggregates return
                $aggregate[@rdf:resource != $not-allowed]/@rdf:resource
    return
        for $uri in $allowed return
            tapi-coll:remove-textgrid-prefix($uri)
};

declare function tapi-coll:remove-textgrid-prefix($uri as xs:string)
as xs:string {
    replace($uri, "textgrid:", "")
};

declare function tapi-coll:make-sequence($collection-type as xs:string)
as map()+ {
    let $uris := tapi-coll:get-uris($collection-type)
    let $aggregations := tapi-coll:get-aggregations($uris)
    let $allowed-manifest-uris := tapi-coll:get-allowed-manifest-uris($aggregations)
    for $manifest-uri in $allowed-manifest-uris return
        try {
            let $manifest-metadata :=  commons:get-metadata-file($manifest-uri)
            let $id := tapi-coll:make-id($collection-type, $manifest-uri)
            let $type := tapi-coll:make-format-type($manifest-metadata)

            return
                map {
                    "@context": "https://gitlab.gwdg.de/subugoe/emo/text-api/-/raw/main/jsonld/sequence.jsonld",
                    "id": $id,
                    "label": tapi-mani:get-manifest-title($manifest-uri),
                    "type": $type
                }
        } catch * {
            util:log("warn", "COLLWARN01: An error occured while processing the manifest with the URI " || $manifest-uri)
        }
};

declare function tapi-coll:make-id($collection-type as xs:string,
    $manifest-uri as xs:string)
as xs:string {
    $commons:server || "/" || $commons:api-prefix || $collection-type || "/" || $manifest-uri || "/manifest.json"
};

declare function tapi-coll:get-format-type($metadata as document-node())
as xs:string {
    $metadata//tgmd:format[1]/string()
    => tapi-coll:make-format-type()
};

declare function tapi-coll:make-format-type($tgmd-format as xs:string)
as xs:string {
    switch ($tgmd-format)
        case "text/tg.aggregation+xml" return "collection"
        case "text/tg.edition+tg.aggregation+xml" return "manifest"
        default return "manifest"
};

declare function tapi-coll:make-annotationCollection-uri($collection-type as xs:string)
as xs:string {
    $commons:server || "/" || $commons:annotation-prefix || $collection-type || "/annotationCollection.json"
};
