declare namespace api = 'http://ossetic-studies.org/ns/abaevdict-api';

declare namespace tei = "http://www.tei-c.org/ns/1.0";

import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at './abv-mod.xqm';

(: ======================================================= :)
(: ==================== API STUFF ======================== :)
(: ======================================================= :)

declare option output:method 'json';
declare option output:json "format=xquery";

declare variable $langs-index := doc('abaevdict_index/langnames.xml');
declare variable $lookup := doc('abaevdict_index/lookup.xml');

(: Get the mentioned index for the right metalanguage :)
declare function api:ment-index($db-lang as xs:string) {
  doc(`abaevdict_index/mentioned_{$db-lang}.xml`)
};

(: Short entry info (only forms for now). Hash is used because URLs don't handle
some Unicode characters very well in this system :)
declare function api:entry-info-short($n as node()) 
as map(xs:string, item()) {
  map{'id': string(hash($n/@xml:id)), 
      'xmlid': string($n/@xml:id), 
      'form': $n/text()
   }
};

declare function api:entry-info-long($n as node(), $db-lang as xs:string) 
as map(xs:string, item()) {
  map:merge(
    (
      api:entry-info-short($n),
      map{'glosses': array:build(data(doc(`abaevdict_{$db-lang}/xml/{$n/@xml:id}.xml`)
        /tei:entry[1]/tei:sense/(tei:sense|tei:sense/tei:sense|.)/tei:cit/tei:quote))}
    )
)
};

(: Short language info -- for the language list :)
declare function api:lang-info-short($n as node(), $db-lang as xs:string) {
  map{
  'id': $n/code/text(),
  'glottolog': $n/glottolog/text(),
  'name': map{'full': if ($db-lang = 'ru') then $n/ru/text() else $n/en/text(),
              'abbr': if ($db-lang = 'ru') then $n/ru/text() else $n/en_abbr/text()}
  }
};

(: Longer info -- for individual languages :)
declare function api:lang-info-full($n as node(), $db-lang as xs:string) {
  map:merge(
    (api:lang-info-short($n, $db-lang),
    map{'words': 
        array:build(api:ment-index($db-lang)/lang-index[1]/lang[@id=$n/code]/word,
        api:word-info-short#1)
      }
    )
  )
};

declare function api:word-info-short($n as node()) {
  let $text := xs:string($n/@text)
  return map{
    (: I am using a hash function as ID, because the words are uniquely
    identified within a language by their text. And the mentioned index is not 
    persistent enough (at least yet) to use persistent ids :)
    'id': string(hash($text)),
    'text': $text
  }
};

declare function api:word-info-long($n as node()) {
  map:merge(
    (
      api:word-info-short($n),
      map{
        'entries': array:build($n/entry,
        fn {
          map{'id': string(hash(./@id)),
              'xmlid': string(./@id),
              'refs': array:build(./ref,
                      fn {
                        map:merge((
                          map:entry('node-id', string(./@node-id)),
                          if(./gloss) then 
                          {'glosses': array:build(distinct-values(./gloss/@text), string#1)}
                          else ()
                        )
                        )
                      })
          }
        }
      )
        (: 'nodes': array:build(string($n/ref/@node-id)),
        'glosses': array:build(string($n/gloss/@text)) :)
      }
    )
  )
};

(: RETURN JSON FOR PLOTLY MAP :)
(: English as default language :)
declare %rest:path("dict/map-info/{$entry}") 
        %rest:GET 
        function api:map-info($entry) {
          (: In this case we do not redirect, but simply give the JSON via 
          another function :)
          api:map-info('en', $entry)
        };

(: This has to be remade to use the /api path. But keep it like this for now :)
declare %rest:path("{$lang}/dict/map-info/{$entry}") 
        %rest:GET 
        function api:map-info($lang, $entry) {
          let $ments := abv-m:make-geomap(doc(`abaevdict_{$lang}/xml/{$entry}.xml`),
                                      $lang)
          return $ments
        };
        
(: API FOR THE MENTIONED INDEX :)
(: Default to English :)
declare %rest:path("/api/{$path=.+}") 
        %rest:GET 
        function api:default($path as xs:string) {
          web:forward(`/en/api/{$path}`)
        };

(: Get languages :)
declare %rest:path("{$db-lang}/api/languages") 
        %rest:GET 
        function api:langs($db-lang as xs:string := 'en') {
          array:build(
            $langs-index/csv[1]/record,
            api:lang-info-short(?,$db-lang)
          )
        };
        
(: Get one language :)
declare %rest:path("{$db-lang}/api/languages/{$lang}") 
        %rest:GET 
        function api:langs-lang($db-lang as xs:string, $lang as xs:string) {
          api:lang-info-full(
            $langs-index/csv[1]/record[code=$lang], $db-lang
          )
        };
        
(: Get words for a language :)
declare %rest:path("{$db-lang}/api/languages/{$lang}/words") 
        %rest:GET 
        function api:langs-lang-words($db-lang as xs:string, $lang as xs:string) {
          array:build(api:ment-index($db-lang)/lang-index[1]/lang[@id=$lang]/word,
            api:word-info-short#1)
        };
        
(: Get info on a particular word. 
Db-lang is a placeholder, it does nothing here, used only for consistency :)
declare %rest:path("{$db-lang}/api/languages/{$lang}/words/{$word-id}") 
        %rest:GET 
        function api:langs-lang-words-word($db-lang as xs:string, 
                                           $lang as xs:string,
                                           $word-id as xs:string) {
          api:word-info-long(
            api:ment-index($db-lang)/lang-index[1]/lang[@id=$lang]/word[string(hash(@text))=$word-id]
          )
        };
        
(: Entry info (only form for now) :)
declare %rest:path("{$db-lang}/api/entries") 
        %rest:GET 
        function api:entries($db-lang as xs:string) {
          array:build(
            $lookup/tei:table[1]/tei:entry,
            api:entry-info-short#1
          )
        };

declare %rest:path("{$db-lang}/api/entries/{$entry-id}") 
        %rest:GET 
        function api:entries($db-lang as xs:string, 
                             $entry-id as xs:string) {
          api:entry-info-long(
            $lookup/tei:table[1]/tei:entry[string(hash(@xml:id))=$entry-id],
            $db-lang)
        };
        
0