:pencil: Improve.

:pencil: Improve.

import module namespace config = "http://apps.28.io/config";
import module namespace api = "http://apps.28.io/api";
import module namespace session = "http://apps.28.io/session";
import module namespace backend = "http://apps.28.io/backend";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace archives = "http://28.io/modules/xbrl/archives";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace labels = "http://28.io/modules/xbrl/labels";

import module namespace sec-filings = "http://28.io/modules/xbrl/profiles/sec/filings";
import module namespace sec-networks = "http://28.io/modules/xbrl/profiles/sec/networks";
import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";

declare option rest:response "first-item";

declare function local:links($component as object, $hypercube as string?) as object
{
  {
    FactTable: backend:url("facttable-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    labels: "true",
                    language: $language
                    }),
    SpreadSheet: backend:url("spreadsheet-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    eliminate: "true",
                    validate: "true",
                    language: $language
                }),
    ModelStructure: backend:url("modelstructure-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    indent: "true",
                    language: $language
                })
  }
};

declare function local:statistics($component as object, $hypercube as string?) as object
{
  let $hypercube as string := ($hypercube, $components:ALL-HYPERCUBES)[1]
  return {
    NumRules: size($component.Rules),
    NumReportElements: components:num-report-elements($component, $hypercube),
    NumHypercubes: components:num-report-elements(
        $component,
        $hypercube,
        "Hypercube"),
    NumDimensions: components:num-report-elements(
        $component,
        $hypercube,
        "Dimension"),
    NumMembers: components:num-report-elements(
        $component,
        $hypercube,
        "Member"),
    NumLineItems: components:num-report-elements(
        $component,
        $hypercube,
        "LineItems"),
    NumAbstracts: components:num-report-elements(
        $component,
        $hypercube,
        "Abstract"),
    NumConcepts: components:num-report-elements(
        $component,
        $hypercube,
        "Concept")
  }
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token              as string? external;
declare  %rest:env                              variable $request-uri        as string  external;
declare  %rest:case-insensitive                 variable $format             as string  external := "json";
declare  %rest:case-insensitive %rest:distinct  variable $cik                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode   as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker             as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $sic                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear         as string* external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod       as string* external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $filingKind         as string* external := ();
declare  %rest:case-insensitive %rest:distinct  variable $eid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $aid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $section            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $networkIdentifier  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $role               as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $hypercube          as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $cid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $reportElement      as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $concept            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure         as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $label              as string* external;
declare  %rest:case-insensitive                 variable $profile-name       as string  external := $config:profile-name;
declare  %rest:case-insensitive                 variable $count              as boolean external := false;
declare  %rest:case-insensitive                 variable $validate           as boolean external := false;
declare  %rest:case-insensitive                 variable $language           as string  external := "en-US";

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $tag as string* := api:preprocess-tags($tag)
let $reportElement := ($reportElement, $concept)
let $section := distinct-values(($section, $networkIdentifier, $role))

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $archives as object* := multiplexer:filings(
  $profile-name,
  $entities,
  $fiscalPeriod,
  $fiscalYear,
  $filingKind,
  $aid)

let $archives-not-found as boolean :=
  exists(($entities, $fiscalPeriod, $fiscalYear, $filingKind, $aid)) and empty($archives)

let $entities as object*  := entities:entities($archives.Entity)
let $components as object* :=
    multiplexer:components(
      $profile-name,
      $archives,
      $cid,
      $reportElement,
      $disclosure,
      $section,
      $label[$profile-name ne "sec"],
      $label[$profile-name eq "sec"]
    )

let $res as object* :=
    for $component in $components
    let $disclosure := switch($profile-name)
                       case "sec" return sec-networks:disclosures($component)
                       default return $component.Profiles.FSA.Disclosure
    where not $disclosure eq "DefaultComponent"
    order by $component.Archive, $component.Label
    let $archive as object? := $archives[archives:aid($$) eq $component.Archive]
    let $entity as object? := $entities[entities:eid($$) = $archive.Entity]
    for $found-hypercube allowing empty in
        hypercubes:hypercubes-for-components($component).Name
    where empty($hypercube) or $found-hypercube = $hypercube
    return {|
      {
        Archive: $component.Archive,
        Section: $component.Label,
        Hypercube: labels:labels(
          $found-hypercube,
          $labels:STANDARD_LABEL_ROLE,
          "en-US",
          $component.Concepts[],
          (),
          ()
        ).$found-hypercube
      },
      local:links($component, $found-hypercube),
      {
        SectionURI: $component.Role,
        HypercubeName: $found-hypercube
      },
      sec-networks:summary($component)[$profile-name eq "sec"],
      if($validate)
      then {
        Validation: [ if(exists($found-hypercube))
                      then components:validation-errors($component, $found-hypercube)
                      else "[ERROR] Missing hypercube"
                    ]
      }
      else (),
      local:statistics($component, $found-hypercube),
      { Disclosure: $disclosure }[$profile-name eq "japan"],
      (: DeprecatedPastThisPoint" :)
      {
        Network: $component.Label,
        NetworkURI: $component.Role
      },
      {
          EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
          CIK : entities:eid($entity),
          FiscalYear :$archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
          FiscalPeriod :$archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus,
          AcceptanceDatetime : sec-filings:acceptance-dateTimes($archive),
          FormType : $archive.Profiles.SEC.FormType
      }[$profile-name eq "sec"]
    |}

let $res := if($format eq "raw")
            then $components
            else $res
let $format := if($format eq "raw")
               then "json"
               else $format

let $result := { Components : [ if($count) then () else $res ] }
let $comment :=
 {
    NumComponents : count($res),
    TotalNumComponents: session:num-components(),
    TotalNumArchives: session:num-archives()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <Components>{
          api:json-to-xml($res.Components[], "Component")
        }</Components>
    },
    to-csv : function($res as object) as string {
        api:json-to-csv($res.Components[])
    }
}

let $results := api:serialize($result, $comment, $serializers, $format, "components")
return switch(true)
       case $entities-not-found return api:not-found("entity")
       case $archives-not-found return api:not-found("archive")
       default return api:check-and-return-results($token, $results, $format)

import module namespace config = "http://apps.28.io/config";
import module namespace api = "http://apps.28.io/api";
import module namespace session = "http://apps.28.io/session";
import module namespace backend = "http://apps.28.io/backend";

import module namespace entities = "http://28.io/modules/xbrl/entities";
import module namespace archives = "http://28.io/modules/xbrl/archives";
import module namespace components = "http://28.io/modules/xbrl/components";
import module namespace hypercubes = "http://28.io/modules/xbrl/hypercubes";
import module namespace labels = "http://28.io/modules/xbrl/labels";

import module namespace sec-filings = "http://28.io/modules/xbrl/profiles/sec/filings";
import module namespace sec-networks = "http://28.io/modules/xbrl/profiles/sec/networks";
import module namespace multiplexer = "http://28.io/modules/xbrl/profiles/multiplexer";

declare option rest:response "first-item";

declare function local:links($component as object, $hypercube as string?) as object
{
  {
    FactTable: backend:url("facttable-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    labels: "true",
                    language: $language
                    }),
    SpreadSheet: backend:url("spreadsheet-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    eliminate: "true",
                    validate: "true",
                    language: $language
                }),
    ModelStructure: backend:url("modelstructure-for-component", {
                    token: $token,
                    aid: $component.Archive,
                    format: $format,
                    section: $component.Role,
                    hypercube: $hypercube,
                    profile-name: $profile-name,
                    indent: "true",
                    language: $language
                })
  }
};

declare function local:statistics($component as object, $hypercube as string?) as object
{
  {
    NumRules: size($component.Rules),
    NumReportElements: components:num-report-elements($component, $hypercube),
    NumHypercubes: components:num-report-elements(
        $component,
        $hypercube,
        "Hypercube"),
    NumDimensions: components:num-report-elements(
        $component,
        $hypercube,
        "Dimension"),
    NumMembers: components:num-report-elements(
        $component,
        $hypercube,
        "Member"),
    NumLineItems: components:num-report-elements(
        $component,
        $hypercube,
        "LineItems"),
    NumAbstracts: components:num-report-elements(
        $component,
        $hypercube,
        "Abstract"),
    NumConcepts: components:num-report-elements(
        $component,
        $hypercube,
        "Concept")
  }
};

(: Query parameters :)
declare  %rest:case-insensitive                 variable $token              as string? external;
declare  %rest:env                              variable $request-uri        as string  external;
declare  %rest:case-insensitive                 variable $format             as string  external := "json";
declare  %rest:case-insensitive %rest:distinct  variable $cik                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $edinetcode   as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $tag                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $ticker             as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $sic                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $fiscalYear         as string* external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $fiscalPeriod       as string* external := "ALL";
declare  %rest:case-insensitive %rest:distinct  variable $filingKind         as string* external := ();
declare  %rest:case-insensitive %rest:distinct  variable $eid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $aid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $section            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $networkIdentifier  as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $role               as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $hypercube          as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $cid                as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $reportElement      as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $concept            as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $disclosure         as string* external;
declare  %rest:case-insensitive %rest:distinct  variable $label              as string* external;
declare  %rest:case-insensitive                 variable $profile-name       as string  external := $config:profile-name;
declare  %rest:case-insensitive                 variable $count              as boolean external := false;
declare  %rest:case-insensitive                 variable $validate           as boolean external := false;
declare  %rest:case-insensitive                 variable $language           as string  external := "en-US";

(: Post-processing :)
let $format as string? := api:preprocess-format($format, $request-uri)
let $fiscalYear as integer* := api:preprocess-fiscal-years($fiscalYear)
let $fiscalPeriod as string* := api:preprocess-fiscal-periods($fiscalPeriod)
let $tag as string* := api:preprocess-tags($tag)
let $reportElement := ($reportElement, $concept)
let $section := distinct-values(($section, $networkIdentifier, $role))

let $cik as string* :=
    switch($profile-name)
    case "sec" return $cik
    case "japan" return $edinetcode
    default return ()

(: Entity resolution :)
let $entities := multiplexer:entities(
  $profile-name,
  $eid,
  $cik,
  $tag,
  $ticker,
  $sic,
  (),
  (),
  (),
  ())

let $entities-not-found as boolean :=
  exists(($eid, $cik, $tag, $ticker, $sic)) and empty($entities)

let $archives as object* := multiplexer:filings(
  $profile-name,
  $entities,
  $fiscalPeriod,
  $fiscalYear,
  $filingKind,
  $aid)

let $archives-not-found as boolean :=
  exists(($entities, $fiscalPeriod, $fiscalYear, $filingKind, $aid)) and empty($archives)

let $entities as object*  := entities:entities($archives.Entity)
let $components as object* :=
    multiplexer:components(
      $profile-name,
      $archives,
      $cid,
      $reportElement,
      $disclosure,
      $section,
      $label[$profile-name ne "sec"],
      $label[$profile-name eq "sec"]
    )

let $res as object* :=
    for $component in $components
    let $disclosure := switch($profile-name)
                       case "sec" return sec-networks:disclosures($component)
                       default return $component.Profiles.FSA.Disclosure
    where not $disclosure eq "DefaultComponent"
    order by $component.Archive, $component.Label
    let $archive as object? := $archives[archives:aid($$) eq $component.Archive]
    let $entity as object? := $entities[entities:eid($$) = $archive.Entity]
    for $found-hypercube allowing empty in
        hypercubes:hypercubes-for-components($component).Name
    where empty($hypercube) or $found-hypercube = $hypercube
    return {|
      {
        Archive: $component.Archive,
        Section: $component.Label,
        Hypercube: labels:labels(
          $found-hypercube,
          $labels:STANDARD_LABEL_ROLE,
          "en-US",
          $component.Concepts[],
          (),
          ()
        ).$found-hypercube
      },
      local:links($component, $found-hypercube),
      {
        SectionURI: $component.Role,
        HypercubeName: $found-hypercube
      },
      sec-networks:summary($component)[$profile-name eq "sec"],
      if($validate and exists($found-hypercube))
      then {
        Validation: [ components:validation-errors($component, $found-hypercube) ]
      }
      else (),
      local:statistics($component, $found-hypercube),
      { Disclosure: $disclosure }[$profile-name eq "japan"],
      (: DeprecatedPastThisPoint" :)
      {
        Network: $component.Label,
        NetworkURI: $component.Role
      },
      {
          EntityRegistrantName : $entity.Profiles.SEC.CompanyName,
          CIK : entities:eid($entity),
          FiscalYear :$archive.Profiles.SEC.Fiscal.DocumentFiscalYearFocus,
          FiscalPeriod :$archive.Profiles.SEC.Fiscal.DocumentFiscalPeriodFocus,
          AcceptanceDatetime : sec-filings:acceptance-dateTimes($archive),
          FormType : $archive.Profiles.SEC.FormType
      }[$profile-name eq "sec"]
    |}

let $res := if($format eq "raw")
            then $components
            else $res
let $format := if($format eq "raw")
               then "json"
               else $format

let $result := { Components : [ if($count) then () else $res ] }
let $comment :=
 {
    NumComponents : count($res),
    TotalNumComponents: session:num-components(),
    TotalNumArchives: session:num-archives()
}
let $serializers := {
    to-xml : function($res as object) as node() {
        <Components>{
          api:json-to-xml($res.Components[], "Component")
        }</Components>
    },
    to-csv : function($res as object) as string {
        api:json-to-csv($res.Components[])
    }
}

let $results := api:serialize($result, $comment, $serializers, $format, "components")
return switch(true)
       case $entities-not-found return api:not-found("entity")
       case $archives-not-found return api:not-found("archive")
       default return api:check-and-return-results($token, $results, $format)