%
% Copyright (C) 2021 Zeping Lee
%

\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
\RequirePackage{xparse}
\ProvidesExplPackage {citation-style-language} {2022-01-22} {v0.1.0}
  {Citation Style Language for LaTeX}

% \msg_new:nnn { citation-style-language } { require-luatex }
%   { LuaTeX~ is~ required~ for~ `citation-style-language'~ package. }
% \sys_if_engine_luatex:F { \msg_fatal:nn { citation-style-language } { require-luatex } }

\sys_if_engine_luatex:T
  { \lua_now:n { csl = require("csl") } }

\RequirePackage { filehook }
\RequirePackage { url }

\cs_new:Npn \csl_incompatible_package:n #1
  {
    \AtBeginOfPackageFile* { #1 }
      { \msg_error:nnn { citation-style-language } { incompatible-package } { #1 } }
  }
\msg_new:nnn { citation-style-language } { incompatible-package }
  { The~ `#1'~ package~ is~ incompatible~ with~ `citeproc'. }

\csl_incompatible_package:n { babelbib }
\csl_incompatible_package:n { backref }
\csl_incompatible_package:n { biblatex }
\csl_incompatible_package:n { bibtopic }
\csl_incompatible_package:n { bibunits }
\csl_incompatible_package:n { chapterbib }
\csl_incompatible_package:n { cite }
\csl_incompatible_package:n { citeref }
\csl_incompatible_package:n { inlinebib }
\csl_incompatible_package:n { jurabib }
\csl_incompatible_package:n { mcite }
\csl_incompatible_package:n { mciteplus }
\csl_incompatible_package:n { multibib }
\csl_incompatible_package:n { natbib }
\csl_incompatible_package:n { splitbib }


\NewDocumentCommand \cslsetup { m }
  { \keys_set:nn { csl } {#1} }

\cs_new:Npn \csloptions #1 { }


\DeclareDocumentCommand \cite { o o m }
  {
    \IfValueTF { #2 }
      { \csl_cite:nnn { #1 } { #2 } { #3 } }
      {
        \IfValueTF { #1 }
          { \csl_cite:nnn { } { #1 } { #3 } }
          { \csl_cite:nnn { } { } { #3 } }
      }
  }


% % multicite command
% \DeclareDocumentCommand \cites { o o m }


\DeclareDocumentCommand \nocite { m }
  {
    \ifx \@begindocumenthook \@undefined \else
      \exp_after:wN \AtBeginDocument
    \fi
      {
        \if@filesw
          \iow_now:Nn \@auxout
            { \citation { { nocite } { #1 } { } } }
        \fi
      }
    \sys_if_engine_luatex:T
      { \lua_now:n { csl.nocite("#1") } }
}


\tl_new:N \l__csl_citation_tl
\tl_new:N \l__csl_citation_id_tl
\tl_new:N \l__csl_cite_items_tl
\tl_new:N \l__csl_note_index_tl
\tl_new:N \l__csl_citation_info_tl

\cs_new:Npn \csl_cite:nnn #1#2#3
  {
    \csl_process_citation_id:n { #3 }
    \csl_process_cite_items:nnn { #1 } { #2 } { #3 }
    \exp_args:NV \csl_process_note_index:n \l__csl_citation_id_tl
    \tl_set:Nx \l__csl_citation_info_tl
      {
        { \l__csl_citation_id_tl }
        { \l__csl_cite_items_tl }
        { \l__csl_note_index_tl }
      }
    \if@filesw
      {
        \iow_now:Nx \@auxout
          { \exp_not:N \citation { \l__csl_citation_info_tl } }
      }
    \fi
    \tl_clear:N \l__csl_citation_tl
    \tl_if_exist:cTF { g__csl_citation_ \l__csl_citation_id_tl _tl }
      {
        \exp_args:Nv \csl_print_defined_citation:n
          { g__csl_citation_ \l__csl_citation_id_tl _tl }
      }
      {
        \bool_if:NTF \l__csl_engine_initialized_bool
          {
            \tl_set:Nx \l__csl_citation_tl
              { \lua_now:e { csl.cite("\l__csl_citation_info_tl") } }
          }
          {
            \exp_args:Nx \csl_print_undefined_citation:n
              { \clist_use:Nn \l__csl_keys_clist { ,~ } }
          }
      }
  }

\cs_new:Npn \csl_print_undefined_citation:n #1
  {
    \tl_set:Nn \l__csl_citation_tl { [ \textbf { #1 } ] }
    \G@refundefinedtrue
    \exp_args:Nnnx \msg_warning:nnn { citation-style-language } { citation / undefined } { #1 }
    \group_begin:
      \reset@font [ \textbf { #1 } ]
    \group_end:
  }

\cs_new:Npn \csl_print_defined_citation:n #1
  {
    \csl_print_defined_citation_aux:nn #1
  }

\cs_new:Npn \csl_print_defined_citation_aux:nn #1#2
  {
    \tl_set:Nn \l__csl_citation_tl { #2 }
    \tl_if_eq:nnTF { #1 } { note }
      { \footnote { #2 } }
      { #2 }
  }


\msg_new:nnn { citation-style-language } { citation / undefined }
  {
    Citation~ `#1'~ on~ page~ \thepage \space undefined~ \msg_line_context: .
  }


\clist_new:N \l__csl_keys_clist
\tl_new:N \l__csl_normalized_keys_tl

% \csl_process_citation_id:n { <cite item ids> }
% It sets the `\l__csl_citation_id_tl` `ITEM-1,ITEM-2@4`.
\cs_new:Npn \csl_process_citation_id:n #1
  {
    \clist_set:Nn \l__csl_keys_clist { #1 }
    \tl_set:Nx \l__csl_normalized_keys_tl
      { \clist_use:Nn \l__csl_keys_clist { , } }
    \int_if_exist:cF { g__csl_citation_count_ \l__csl_normalized_keys_tl _int }
      {
        \int_gzero_new:c
          { g__csl_citation_count_ \l__csl_normalized_keys_tl _int }
      }
    \int_gincr:c { g__csl_citation_count_ \l__csl_normalized_keys_tl _int }
    \tl_set:Nx \l__csl_citation_id_tl
      {
        \l__csl_normalized_keys_tl @
        \int_use:c { g__csl_citation_count_ \l__csl_normalized_keys_tl _int }
      }
  }


\tl_new:N \l__csl_cite_item_tl

% `{citationID}{{id={id1},{}},{}}{<noteIndex>}`
\cs_new:Npn \csl_process_cite_items:nnn #1#2#3
  {
    \tl_clear:N \l__csl_cite_items_tl
    \clist_map_inline:nn { #3 }
      {
        \tl_if_empty:NTF \l__csl_cite_items_tl
          {
            \csl_process_cite_item:nnn { #1 } { #2 } { ##1 }
            \tl_put_right:Nx \l__csl_cite_items_tl { { \l__csl_cite_item_tl } }
          }
          {
            \csl_process_cite_item:nnn { } { } { ##1 }
            \tl_put_right:Nx \l__csl_cite_items_tl { , { \l__csl_cite_item_tl } }
          }
      }
  }


\prop_new:N \l__csl_cite_item_prop

\keys_define:nn { csl / cite-item }
  {
    prefix .prop_put:N = \l__csl_cite_item_prop,
    suffix .prop_put:N = \l__csl_cite_item_prop,
    locator .prop_put:N = \l__csl_cite_item_prop,
    label .prop_put:N = \l__csl_cite_item_prop,
    suppress-author .prop_put:N = \l__csl_cite_item_prop,
    author-only .prop_put:N = \l__csl_cite_item_prop,
    uris .prop_put:N = \l__csl_cite_item_prop,
    book .code:n = { \csl_set_locator:nn { book } { #1 } } ,
    chapter .code:n = { \csl_set_locator:nn { chapter } { #1 } } ,
    column .code:n = { \csl_set_locator:nn { column } { #1 } } ,
    figure .code:n = { \csl_set_locator:nn { figure } { #1 } } ,
    folio .code:n = { \csl_set_locator:nn { folio } { #1 } } ,
    issue .code:n = { \csl_set_locator:nn { issue } { #1 } } ,
    line .code:n = { \csl_set_locator:nn { line } { #1 } } ,
    note .code:n = { \csl_set_locator:nn { note } { #1 } } ,
    opus .code:n = { \csl_set_locator:nn { opus } { #1 } } ,
    page .code:n = { \csl_set_locator:nn { page } { #1 } } ,
    paragraph .code:n = { \csl_set_locator:nn { paragraph } { #1 } } ,
    part .code:n = { \csl_set_locator:nn { part } { #1 } } ,
    section .code:n = { \csl_set_locator:nn { section } { #1 } } ,
    sub-verbo .code:n = { \csl_set_locator:nn { sub-verbo } { #1 } } ,
    verse .code:n = { \csl_set_locator:nn { verse } { #1 } } ,
    volume .code:n = { \csl_set_locator:nn { volume } { #1 } } ,
  }

\cs_new:Npn \csl_set_locator:nn #1#2
  {
    \prop_put:Nnn \l__csl_cite_item_prop { label } { #1 }
    \prop_put:Nnn \l__csl_cite_item_prop { locator } { #2 }
  }

\tl_new:N \l__csl_prefix_tl
\tl_new:N \l__csl_suffix_tl

% \csl_process_cite_item:nnn { <prenote> } { <postnote> } { <item ID> }
% return: `id={ITEM},locator={42},label={page}`
\cs_new:Npn \csl_process_cite_item:nnn #1#2#3
  {
    \prop_clear:N \l__csl_cite_item_prop
    \prop_put:Nnn \l__csl_cite_item_prop { id } { #3 }
    \tl_if_empty:nF { #1 }
      {
        \tl_set:Nn \l__csl_prefix_tl { #1 }
        \tl_put_right:NV \l__csl_prefix_tl \l__csl_prefix_separator_tl
        \prop_put:NnV \l__csl_cite_item_prop { prefix } { \l__csl_prefix_tl }
      }
    \tl_if_in:nnTF { #2 } { = }
      {
        \keys_set:nn { csl / cite-item } { #2 }
      }
      {
        \tl_if_empty:nF { #2 }
          {
            \regex_match:nnTF { \d+ } { #2 }
              { \csl_set_locator:nn { page } { #2 } }
              {
                \tl_set:Nn \l__csl_suffix_tl { #2 }
                \tl_put_left:NV \l__csl_suffix_tl \l__csl_suffix_separator_tl
                \prop_put:NnV \l__csl_cite_item_prop { suffix } { \l__csl_suffix_tl }
              }
          }
      }
    \tl_clear:N \l__csl_cite_item_tl
    \prop_map_inline:Nn \l__csl_cite_item_prop
      {
        \tl_if_empty:NF \l__csl_cite_item_tl
          { \tl_put_right:Nn \l__csl_cite_item_tl { , } }
        \tl_put_right:Nn \l__csl_cite_item_tl { ##1 = { ##2 } }
      }
  }

\int_new:N \l__csl_note_index_int
\int_gzero_new:N \g__csl_last_note_index_int
\int_gzero_new:N \g__csl_citation_note_count_int

% \csl_process_note_index:nnn { <citation ID> }
\cs_new:Npn \csl_process_note_index:n #1
  {
    \int_set_eq:Nc \l__csl_note_index_int { c@ \@mpfn }
    \tl_if_exist:cTF { g__csl_citation_ #1 _tl }
      { \int_incr:N \l__csl_note_index_int }
      { \int_gincr:N \g__csl_citation_note_count_int }
    \int_add:Nn \l__csl_note_index_int { \g__csl_citation_note_count_int }
    \tl_set:Nx \l__csl_note_index_tl
      { \int_use:N \l__csl_note_index_int }
    \int_gset_eq:NN \g__csl_last_note_index_int \l__csl_note_index_int
    \int_compare:nT { \l__csl_note_index_int < \g__csl_last_note_index_int }
      {
        \int_gzero:N \g__csl_last_note_index_int
        \int_gzero:N \g__csl_citation_note_count_int
      }
  }


% Used in aux files to register cite items.
\cs_set:Npn \citation #1
  {
    \sys_if_engine_luatex:T
      { \lua_now:n { csl.register_citation_info("#1") } }
  }


\cs_new:Npn \cslcite #1#2
  {
    \bibcite { #1 } { #2 }
    \if@filesw
      \iow_now:Nn \@auxout { \bibcite { #1 } { #2 } }
    \fi
  }


\cs_set:Npn \bibcite #1#2
  {
    \tl_gset:cn { g__csl_citation_ #1  _tl } { #2 }
  }

% The `babel` package redefines \bibcite in the \@begindocumenthook.
% This should be disabled.
\AtEndOfPackageFile* { babel }
  {
    \cs_set_eq:NN \bbl@cite@choice \relax
  }

\AtEndOfPackageFile* { hyperref }
  {
    \cs_set:Npn \bibcite #1#2
      {
        \tl_gset:cn { g__csl_citation_ #1  _tl } { #2 }
      }
  }

\NewDocumentCommand \printbibliography { }
  {
    \sys_if_engine_luatex:TF
      {
        \bool_if:NTF \l__csl_engine_initialized_bool
          { \lua_now:n { csl.bibliography() } }
          { \msg_warning:nnn { citation-style-language } { bibliography / empty } }
      }
      {
        \tl_if_empty:NTF \l__csl_bibliography_tl
          {
            \file_if_exist_input:nF { \jobname .bbl }
              {
                \msg_warning:nnx { citation-style-language } { file / non-exist} { \jobname .bbl }
              }
          }
          { \exp_args:NV \csl_print_bibiliography_tl \l__csl_bibliography_tl }
      }
  }

\cs_new:Npn \csl_print_bibliography_tl #1
  {
    \begin { thebibliography }
      #1
    \end { thebibliography }
  }

\msg_new:nnn { citation-style-language } { bibliography / empty }
  { The~ bibliography~ is~ empty.  }

\msg_new:nnn { citation-style-language } { file / non-exist }
  { No~ file~ #1. }


\tl_new:N \l__csl_style_tl
\clist_new:N \l__csl_bib_resources_clist
\tl_new:N \l__csl_prefix_separator_tl
\tl_new:N \l__csl_suffix_separator_tl
\tl_new:N \l__csl_locale_tl
\tl_new:N \l__csl_bib_font_tl
\tl_new:N \l__csl_bib_item_sep_tl
\tl_new:N \l__csl_bib_hang_tl
\bool_new:N \l__csl_hanging_indent_bool
\tl_new:N \l__csl_line_spacing_tl
\tl_new:N \l__csl_entry_spacing_tl


\keys_define:nn { csl }
  {
    style .tl_set:N = \l__csl_style_tl ,
    prefix-separator .tl_set:N = \l__csl_prefix_separator_tl ,
    suffix-separator .tl_set:N = \l__csl_suffix_separator_tl ,
    locale .tl_set:N = \l__csl_locale_tl ,
    bib-font .tl_set:N = \l__csl_bib_font_tl ,
    bib-item-sep .tl_set:N = \l__csl_bib_item_sep_tl ,
    bib-hang .tl_set:N = \l__csl_bib_hang_tl ,
    hanging-indent .bool_set:N = \l__csl_hanging_indent_bool ,
    line-spacing .tl_set:N = \l__csl_line_spacing_tl ,
    entry-spacing .tl_set:N = \l__csl_entry_spacing_tl ,
  }

\keys_set:nn { csl }
  {
    prefix-separator = { ~ } ,
    suffix-separator = { , ~ } ,
    bib-hang = { 1 em } ,
    line-spacing = { 1 } ,
    entry-spacing = { 1 } ,
  }

\bool_new:N \l__csl_engine_initialized_bool

\prop_set_from_keyval:Nn \l__csl_babel_locale_mapping_prop
  {
    acadian         = fr-CA,
    american        = en-US,
    australian      = en-AU,
    afrikaans       = af-ZA,
    albanian        = sq-AL,
    amharic         = am-ET,
    arabic          = ar,
    armenian        = hy-AM,
    asturian        = ast-ES,
    austrian        = de-AT,
    bahasa          = id-ID,
    bahasai         = id-ID,
    bahasam         = id-ID,
    basque          = eu-ES,
    bengali         = bn-BD,
    bgreek          = el-GR,
    brazil          = pt-BR,
    brazilian       = pt-BR,
    breton          = br-FR,
    british         = en-GB,
    bulgarian       = bg-BG,
    canadian        = en-CA,
    canadien        = fr-CA,
    catalan         = ca-AD,
    coptic          = cop,
    croatian        = hr-HR,
    czech           = cs-CZ,
    danish          = da-DK,
    divehi          = dv-MV,
    dutch           = nl-NL,
    english         = en-US,
    esperanto       = eo-001,
    estonian        = et-EE,
    ethiopia        = am-ET,
    farsi           = fa-IR,
    finnish         = fi-FI,
    francais        = fr-FR,
    french          = fr-FR,
    frenchle        = fr-FR,
    friulan         = fur-IT,
    galician        = gl-ES,
    german          = de-DE,
    germanb         = de-DE,
    greek           = el-GR,
    hebrew          = he-IL,
    hindi           = hi-IN,
    ibygreek        = el-CY,
    icelandic       = is-IS,
    indon           = id-ID,
    indonesia       = id-ID,
    interlingua     = ia-FR,
    irish           = ga-IE,
    italian         = it-IT,
    japanese        = ja-JP,
    kannada         = kn-IN,
    lao             = lo-LA,
    latin           = la-Latn,
    latvian         = lv-LV,
    lithuanian      = lt-LT,
    lowersorbian    = dsb-DE,
    lsorbian        = dsb-DE,
    magyar          = hu-HU,
    malay           = id-ID,
    malayalam       = ml-IN,
    marathi         = mr-IN,
    meyalu          = id-ID,
    mongolian       = mn-Cyrl,
    naustrian       = de-AT,
    newzealand      = en-NZ,
    ngerman         = de-DE,
    nko             = ha-NG,
    norsk           = nb-NO,
    norwegian       = nn-NO,
    nynorsk         = nn-NO,
    occitan         = oc-FR,
    piedmontese     = pms-IT,
    pinyin          = pny,
    polish          = pl-PL,
    polutonikogreek = el-GR,
    portuges        = pt-PT,
    portuguese      = pt-PT,
    romanian        = ro-RO,
    romansh         = rm-CH,
    russian         = ru-RU,
    samin           = se-NO,
    sanskrit        = sa-IN,
    scottish        = gd-GB,
    serbian         = sr-Latn,
    serbianc        = sr-Cyrl,
    slovak          = sk-SK,
    slovene         = sl-SI,
    slovenian       = sl-SI,
    spanish         = es-ES,
    swedish         = sv-SE,
    swiss           = de-CH,
    swissgerman     = de-CH,
    nswissgerman    = de-CH,
    syriac          = syc,
    tamil           = ta-IN,
    telugu          = te-IN,
    thai            = th-TH,
    thaicjk         = th-TH,
    tibetan         = bo-CN,
    turkish         = tr-TR,
    turkmen         = tk-TM,
    ukrainian       = uk-UA,
    urdu            = ur-IN,
    UKenglish       = en-UK,
    uppersorbian    = hsb-DE,
    USenglish       = en-US,
    usorbian        = hsb-DE,
    vietnamese      = vi-VN,
    welsh           = cy-GB,
  }

\tl_new:N \l__csl_bibliography_tl
\tl_new:N \l__csl_bibliography_setup_tl

\AtBeginDocument
  {
    \tl_if_empty:NTF \l__csl_style_tl
      { \tl_set_eq:NN \l__csl_style_tl \g__csl_aux_bibstyle_tl }
      { \exp_args:Nx \csl_write_aux_bibstyle:n { \l__csl_style_tl } }
    \clist_if_empty:NTF \l__csl_bib_resources_clist
      { \clist_set_eq:NN \l__csl_bib_resources_clist \g__csl_aux_bib_files_clist }
      {
        \exp_args:Nx \csl_write_aux_bibdata:n
          { \clist_use:Nn \l__csl_bib_resources_clist { , } }
      }
    \csl_write_aux_csl_options:
    \sys_if_engine_luatex:T
      {
        \lua_now:e
          {
            csl.init(
              "\l__csl_style_tl",
              "\l__csl_bib_resources_clist",
              "\l__csl_locale_tl"
            )
          }
        \str_if_eq:eeT { \lua_now:n { tex.print(csl.initialized) } } { true }
          { \bool_set_true:N \l__csl_engine_initialized_bool }
        \@ifpackageloaded { hyperref }
          { \lua_now:n { csl.enable_linking() } }
          { }
      }
    % Load .bbl at the beginning of document to save one pass of latex.
    % In this procedure, the \cslcite command is processed and the contents
    % of `thebibliography` is stored into \l__csl_bibliography_tl.
    \group_begin:
      \RenewDocumentCommand \cslsetup { m }
        { \tl_set:Nn \l__csl_bibliography_setup_tl { #1 } }
      \RenewDocumentEnvironment { thebibliography } { m +b }
        { \tl_set:Nn \l__csl_bibliography_tl { { #1 } #2 } }
        { }
      \file_if_exist_input:n { \jobname .bbl }
    \group_end:
  }

\cs_new:Npn \csl_write_aux_bibstyle:n #1
  {
    \if@filesw
      \iow_now:Nn \@auxout { \bibstyle { #1 } }
    \fi
  }

\clist_new:N \l__csl_options_clist

\cs_new:Nn \csl_write_aux_csl_options:
  {
    \clist_clear:N \l__csl_options_clist
    % locale
    \tl_if_empty:NT \l__csl_locale_tl
      {
        \tl_if_exist:NT \bbl@main@language
          {
            \prop_get:NVN \l__csl_babel_locale_mapping_prop \bbl@main@language
              \l__csl_locale_tl
          }
      }
    \tl_if_empty:NF \l__csl_locale_tl
      {
        \clist_put_right:Nx \l__csl_options_clist
          { locale = \l__csl_locale_tl }
      }
    % linking
    \@ifpackageloaded { hyperref }
      { \clist_put_right:Nn \l__csl_options_clist { linking = true } }
      { }
    % write to aux file
    \prop_if_empty:NF \l__csl_options_clist
      {
        \if@filesw
          \iow_now:Nx \@auxout
            {
              \exp_not:N \csloptions
                { \clist_use:Nn \l__csl_options_clist { , } }
            }
        \fi
      }
  }


\DeclareDocumentCommand \bibliographystyle { m }
  {
    \ifx \@begindocumenthook \@undefined
      \csl_write_aux_bibstyle:n { #1 }
    \fi
    \tl_set:Nn \l__csl_style_tl { #1 }
  }

\tl_new:N \g__csl_aux_bibstyle_tl
\cs_set:Npn \bibstyle #1
  { \tl_gset:Nn \g__csl_aux_bibstyle_tl { #1 } }


\NewDocumentCommand \addbibresource { o m }
  { \clist_put_right:Nn \l__csl_bib_resources_clist { #2 } }


\clist_new:N \g__csl_aux_bib_files_clist
\cs_set:Npn \bibdata #1
  { \clist_gput_right:Nn \g__csl_aux_bib_files_clist { #1 } }


\DeclareDocumentCommand \bibliography { m }
  {
    \csl_write_aux_bibdata:n { #1 }
    \printbibliography
  }

\cs_new:Npn \csl_write_aux_bibdata:n #1
  {
    \if@filesw
      \iow_now:Nn \@auxout { \bibdata { #1 } }
    \fi
  }


\clist_new:N \g__csl_bib_items_clist

% For numeric or label-style bibliography
% \def\@lbibitem[#1]#2{\item[\@biblabel{#1}\hfill]\if@filesw
%       {\let\protect\noexpand
%        \immediate
%        \write\@auxout{\string\bibcite{#2}{#1}}}\fi\ignorespaces}
\cs_new:Npn \csl_lbibitem:nn [#1]#2
  {
    \clist_gput_right:Nn \g__csl_bib_items_clist { #2 }
    \item [ \@biblabel { #1 } \hfill ] \ignorespaces
  }
\cs_set_eq:NN \@lbibitem \csl_lbibitem:nn

% For author-date bibliography
% \def\@bibitem#1{\item\if@filesw \immediate\write\@auxout
%        {\string\bibcite{#1}{\the\value{\@listctr}}}\fi\ignorespaces}
\cs_new:Npn \csl_bibitem:n #1
  {
    \clist_gput_right:Nn \g__csl_bib_items_clist { #1 }
    \item [ ] \ignorespaces
  }
\cs_set_eq:NN \@bibitem \csl_bibitem:n

\AtEndOfPackageFile* { hyperref }
  {
    \cs_gset_eq:NN \@lbibitem \csl_lbibitem:nn
    \cs_gset_eq:NN \@bibitem \csl_bibitem:n
  }

% CSL outputs the whole label thus the brackets are removed from \@biblabel
% \def\@biblabel#1{[#1]}
\cs_set:Npn \@biblabel #1 { #1 }


\cs_if_exist:cTF { chapter }
  {
    \cs_set:Nn \csl_bib_section:
      {
        \chapter *
          {
            \bibname
            \@mkboth
              { \MakeUppercase { \bibname } }
              { \MakeUppercase { \bibname } }
          }
      }
  }
  {
    \cs_set:Nn \csl_bib_section:
      {
        \section *
          {
            \refname
            \@mkboth
              { \MakeUppercase { \refname } }
              { \MakeUppercase { \refname } }
          }
      }
  }

\tl_new:N \l__csl_bib_preamble_tl

\tl_new:N \l__csl_bib_postamble_tl

\dim_new:N \l__csl_bib_hang_dim
\skip_new:N \l__csl_bib_item_sep_skip

\cs_new:Npn \csl_set_bib_label_spacing:n #1
  {
    \bool_if:NTF \l__csl_hanging_indent_bool
      {
        \dim_set:Nn \l__csl_bib_hang_dim { \l__csl_bib_hang_tl }
        \dim_set_eq:NN \leftmargin \l__csl_bib_hang_dim
        \dim_set:Nn \itemindent { - \leftmargin }
      }
      {
        \settowidth \labelwidth { \@biblabel { #1 } }
        \dim_set_eq:NN \leftmargin \labelwidth
        \dim_add:Nn \leftmargin { \labelsep }
      }
  }

\cs_new:Nn \csl_set_bib_item_sep:
  {
    \skip_zero:N \parsep
    \tl_if_empty:NTF \l__csl_bib_item_sep_tl
      {
        \skip_set:Nn \l__csl_bib_item_sep_skip
          {
            8 pt plus 4 pt minus 2 pt * \dim_ratio:nn { 1 em } { 8 pt }
            * \l__csl_entry_spacing_tl
          }
      }
      { \skip_set:Nn \l__csl_bib_item_sep_skip { \l__csl_bib_item_sep_tl } }
  }

\cs_new:Nn \csl_set_bib_allow_break:
  {
    \sloppy
    \int_set:Nn \clubpenalty { 4000 }
    \int_set_eq:NN \@clubpenalty \clubpenalty
    \int_set:Nn \widowpenalty { 4000 }
    % \sfcode`\.\@m
    \frenchspacing
  }
% TODO: \biburlsetup

\cs_new_eq:NN \csl_set_bib_page_break: \csl_set_bib_allow_break:

\cs_new:Nn \csl_set_bib_no_break:
  {
    \sloppy
    \int_set:Nn \interlinepenalty { 5000 }
    \int_set:Nn \widowpenalty { 10000 }
    \int_set:Nn \clubpenalty { 10000 }
    \int_set_eq:NN \@clubpenalty \clubpenalty
    \raggedbottom
    \frenchspacing
  }

% It will be used for multi-bibliography.
\cs_new:Nn \csl_reset_bib_format:
  {
    \keys_set:nn { csl } {
      hanging-indent = false ,
      line-spacing = 1 ,
      entry-spacing = 1 ,
    }
  }

% \newenvironment{thebibliography}[1]
\RenewDocumentEnvironment { thebibliography } { m }
  {
    \csl_bib_section:
    \dim_zero:N \parindent
    \l__csl_bib_preamble_tl
    \tl_if_eq:NnF \l__csl_line_spacing_tl { 1 }
      { \linespread { \l__csl_line_spacing_tl } \selectfont }
    \l__csl_bib_font_tl
    \list { }
      {
        \csl_set_bib_label_spacing:n { #1 }
        \csl_set_bib_item_sep:
      }
    \sloppy
    \csl_set_bib_page_break:
    \frenchspacing
    \clist_gclear:N \g__csl_bib_items_clist
  }
  {
    \l__csl_bib_postamble_tl
    \tl_set:Nn \@noitemerr
      { \msg_warning:nnn { citation-style-language } { bibliography / empty } }
    \endlist
    \csl_reset_bib_format:
  }

\endinput
