%D \module
%D   [       file=font-fil,
%D        version=2011.01.13, % (copied fron font-ini)
%D          title=\CONTEXT\ Font Macros,
%D       subtitle=Classes and Files,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{ConTeXt Font Macros / Classes and Files}

\unprotect

%D Personally I think that using \TEX\ macro packages is complicated by the way
%D fonts are handled. Apart from the many encodings, we also deal with different
%D naming schemes. Confronted with this problem, I decided to change the definitions
%D into:
%D
%D \starttyping
%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
%D \stoptyping
%D
%D combined with for instance:
%D
%D \starttyping
%D \definefontsynonym [Times-Roman] [tir]
%D \stoptyping

% \definetypeface[palatino][rm][serif][palatino,allbold][default]
%
% \startfontclass[palatino]
%   \definefontsynonym [Serif]        [SerifBold]
%   \definefontsynonym [SerifItalic]  [SerifBoldItalic]
%   \definefontsynonym [SerifSlanted] [SerifBoldSlanted]
%   \definefontsynonym [SerifCaps]    [SerifBold]
% \stopfontclass
%
% \setupbodyfont[palatino]

\permanent\protected\tolerant\protected\def\startfontclass[#class]%
  {\push_macro_fontclass
   \ifcstok{#class}\v!each
     \lettonothing\fontclass
 % \orelse\iftok{#class}\emptytoks
 %   % keep old
   \else
     \cdef\fontclass{#class}%
   \fi}

\permanent\protected\def\stopfontclass
  {\pop_macro_fontclass}

\permanent\def\classfont#class#name{#class#name} % \definefont[whatever][\classfont{xx}{yy} at 10pt]

%D \macros
%D   {definefontsynonym, doifelsefontsynonym,
%D    expandfontsynonym, truefontname, truefontdata}
%D
%D While looking for fonts, fontsynonyms are used for accessing the files!
%D
%D \starttyping
%D \definefontsynonym[Serif][Lucida-Bright]
%D \definefontsynonym[Lucida-Bright][lbr][encoding=texnansi]
%D \stoptyping

\installcorenamespace {fontfile} % file synonyms

\lettonothing\m_font_name
\lettonothing\m_font_file

\mutable\def\defaultfontfile{\truefontname{Normal}} % was cmtt10, but that one is gone

\permanent\protected\def\definefontsynonym[#name]#spacer[#file]%
  {\edef\m_font_name{#name}%
   \edef\m_font_file{#file}%
   \ifempty\fontclass
      \expandafter\font_basics_define_font_synonym_nop
   \else
      \expandafter\font_basics_define_font_synonym_yes
   \fi}

\protected\def\font_basics_define_font_synonym_nop
  {\letcsname\??fontfile\m_font_name\endcsname\m_font_file
   \doifelsenextoptionalcs\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil}

\protected\def\font_basics_define_font_synonym_yes
  {\letcsname\??fontfile\fontclass\m_font_name\endcsname\m_font_file
   \doifelsenextoptionalcs\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil}

\permanent\protected\def\edefinefontsynonym[#name]#spacer[#file]%
  {\edef\m_font_name{#name}%
   \edef\m_font_file{#file}%
   \ifempty\fontclass
      \expandafter\font_basics_define_font_synonym_nop_expanded
   \else
      \expandafter\font_basics_define_font_synonym_yes_expanded
   \fi}

\protected\def\font_basics_define_font_synonym_nop_expanded#ignore[#spec]%
  {\letcsname\??fontfile\m_font_name\endcsname\m_font_file
   \expanded{\font_basics_define_font_synonym_nop_opt[#spec]}}

\protected\def\font_basics_define_font_synonym_yes_expanded#ignore[#spec]%
  {\letcsname\??fontfile\fontclass\m_font_name\endcsname\m_font_file
   \expanded{\font_basics_define_font_synonym_yes_opt[#spec]}}

\let\p_features  \undefined
\let\p_fallbacks \undefined
\let\p_goodies   \undefined
\let\p_designsize\undefined

\protected\def\font_basics_define_font_synonym_nop_opt[#specification]%
  {\let\p_features  \undefined
   \let\p_fallbacks \undefined
   \let\p_goodies   \undefined
   \let\p_designsize\undefined
   \expandafter\font_basics_get_font_parameter_nop#specification,\ignorearguments}

\protected\def\font_basics_define_font_synonym_yes_opt[#specification]%
  {\let\p_features  \undefined
   \let\p_fallbacks \undefined
   \let\p_goodies   \undefined
   \let\p_designsize\undefined
   \expandafter\font_basics_get_font_parameter_yes#specification,\ignorearguments}

% todo: check if we can use \edef but then we need to protect \mathsizesuffix .. in fact that
% can be default then: \let\mathsizesuffix\relax .. i need to play with it first

\def\font_basics_get_font_parameter_nop#key=#value,%
  {\ifarguments
     \font_basics_get_font_parameter_nop_finish
   \else
     \defcsname p_#key\endcsname{#value}%  % no edef as we need to keep \mathsizesuffix
     \expandafter\font_basics_get_font_parameter_nop
   \fi}

\def\font_basics_get_font_parameter_yes#key=#value,%
  {\ifarguments
     \font_basics_get_font_parameter_yes_finish
   \else
     \defcsname p_#key\endcsname{#value}%  % no edef as we need to keep \mathsizesuffix
     \expandafter\font_basics_get_font_parameter_yes
   \fi}

% helpers, some day these will be toks and counts

% \def\fntsetdefname {\glet\somefontname\defaultfontfile}
% \def\fntsetsomename{\gdef\somefontname} % takes argument
% \def\fntsetnopsize {\lettonothing\somefontsize}
% \def\fntsetsomesize{\def\somefontsize}  % takes argument

% happens later, else mkvi parsing gets into troubles

% end of helpers

% we could collect them in one macro (but no expansion)

\def\font_basics_define_font_synonym_nop_nil
  {\letcsname\??fontfile\m_font_name\s!features  \endcsname\undefined
   \letcsname\??fontfile\m_font_name\s!fallbacks \endcsname\undefined
   \letcsname\??fontfile\m_font_name\s!goodies   \endcsname\undefined
   \letcsname\??fontfile\m_font_name\s!designsize\endcsname\undefined}

\def\font_basics_define_font_synonym_yes_nil
  {\gletcsname\??fontfile\fontclass\m_font_name\s!features  \endcsname\undefined
   \gletcsname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\undefined
   \gletcsname\??fontfile\fontclass\m_font_name\s!goodies   \endcsname\undefined
   \gletcsname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\undefined}

\def\font_basics_get_font_parameter_nop_finish
  {\letcsname\??fontfile\m_font_name\s!features  \endcsname\p_features
   \letcsname\??fontfile\m_font_name\s!fallbacks \endcsname\p_fallbacks
   \letcsname\??fontfile\m_font_name\s!goodies   \endcsname\p_goodies
   \letcsname\??fontfile\m_font_name\s!designsize\endcsname\p_designsize}

\def\font_basics_get_font_parameter_yes_finish
  {\gletcsname\??fontfile\fontclass\m_font_name\s!features  \endcsname\p_features
   \gletcsname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\p_fallbacks
   \gletcsname\??fontfile\fontclass\m_font_name\s!goodies   \endcsname\p_goodies
   \gletcsname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\p_designsize}

%\definefontsynonym [KopFont] [\fontclassname{officina}{SerifBold}]
%\defineclassfontsynonym [KopFont] [officina] [SerifBold]
%\definefontsynonym[#tag][\fontclassname{#class}{#fileortag}]}

\permanent\tolerant\protected\def\defineclassfontsynonym[#tag]#spacer[#class]#spacer[#fileortag]% needs testing
  {\defcsname\??fontfile\fontclass#tag\endcsname{\fontclassname{#class}{#fileortag}}%
   \font_basics_define_font_synonym_yes_nil}

\aliased\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater

\permanent\tolerant\protected\def\setupfontsynonym[#name]#spacer[#settings]% not yet supported, will do when needed
  {}

% todo: replace * by ... less messy with features

% no \ifempty here as #1 can be empty

\permanent\def\truefontname#name%
  {\expandafter\font_helpers_true_fontname#name*\empty*\relax}

\def\font_helpers_true_fontname#name*#first#rest*#ignore\relax
  {\ifcsname\??fontfile\fontclass#name\endcsname
     \ifx#first\empty
       \expandafter\truefontname\lastnamedcs
     \else
       \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
     \fi
   \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
     \ifx#first\empty
       \expandafter\truefontname\lastnamedcs
     \else
       \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
     \fi
   \orelse\ifcsname\??fontfile#name\endcsname
     \ifx#first\empty
       \expandafter\truefontname\lastnamedcs
     \else
       \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest%
     \fi
   \else
     #name\ifx#first\empty\else*#first#rest\fi
   \fi}

\def\font_helpers_true_fontname_check#name%
  {\expandafter\font_helpers_true_fontname_check_indeed#name*\relax}

\def\font_helpers_true_fontname_check_indeed#name*#ignore\relax
  {\ifcsname\??fontfile\fontclass#name\endcsname
     \expandafter\font_helpers_true_fontname_check\lastnamedcs
   \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
     \expandafter\font_helpers_true_fontname_check\lastnamedcs
   \orelse\ifcsname\??fontfile#name\endcsname
     \expandafter\font_helpers_true_fontname_check\lastnamedcs
   \else
     #name%
   \fi}

% ok when the last lookup is not stripped .. we need to be able to define synonyms for symbols

% \normaldef is needed for the mkvi parser

\permanent\def\expandfontsynonym#command#name% one level expansion
  {\ifcsname\??fontfile\fontclass#name\endcsname
     \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}%
   \orelse\ifcsname\??fontfile\defaultfontclass#2\endcsname
     \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}%
   \fi}

\permanent\def\doifelsefontsynonym#name%
  {\ifcsname\??fontfile\fontclass#name\endcsname
     \expandafter\firstoftwoarguments
   \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doiffontsynonymelse\doifelsefontsynonym

%D \macros
%D   {tracedfontname}
%D
%D A goody:

\permanent\def\tracedfontname#name%
  {#name\ifcsname\??fontfile\fontclass#name\endcsname
    %\expandafter\tracedfontname\csname\??fontfile\fontclass#name\endcsname
     \expandafter\tracedfontname\lastnamedcs
   \orelse\ifcsname\??fontfile#name\endcsname
    %\expandafter\tracedfontname\csname\??fontfile#name\endcsname
     \expandafter\tracedfontname\lastnamedcs
   \fi}

%D \macros
%D   {fontclass, defaultfontclass}
%D
%D The fontclass model was introduced a while after we implement the basic font
%D model and at that time we still defaulted to no model at all. Nowadays we default
%D to the \type {modern} fontclass.

\lettonothing\fontclass
\lettonothing\defaultfontclass

\permanent\def\fontclassname#class#name% tricky ... no lastnamedcs here due to nesting
  {\ifcsname\??fontfile#class#name\endcsname
     \fontclassname{#class}{\csname\??fontfile#class#name\endcsname}%
   \orelse\ifcsname\??fontfile#name\endcsname
     \fontclassname{#class}{\csname\??fontfile#name\endcsname}%
   \else
     #2%
   \fi}

\installmacrostack\fontclass

%D Files or names can have properties and these need to be consulted at some point.
%D They can inherit them.

% Why these expanded and rscale not ... maybe not worth the trouble (delayed
% expansion actually would be better i.e. macros in feature specs). Test without
% pre-expansion.

\def\font_helpers_update_font_class_parameters
  {\edef\m_font_class_features  {\begincsname\??fontclass\fontclass\fontstyle\s!features  \endcsname}%
   \edef\m_font_class_fallbacks {\begincsname\??fontclass\fontclass\fontstyle\s!fallbacks \endcsname}%
   \edef\m_font_class_goodies   {\begincsname\??fontclass\fontclass\fontstyle\s!goodies   \endcsname}%
   \edef\m_font_class_designsize{\begincsname\??fontclass\fontclass\fontstyle\s!designsize\endcsname}}

% resolve

% \def\font_helpers_set_features_yes#name%
%   {\ifcsname\??fontfile\fontclass#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse          % class + symbolic_name
%    \ifcsname\??fontfile          #name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse          % symbolic_name
%    \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \orelse % class + parent_name
%    \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \else   % parent_name
%    \lettonothing\m_font_features\fi}
%
% \def\font_helpers_set_fallbacks_yes#name%
%   {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
%    \ifcsname\??fontfile          #name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
%    \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \orelse
%    \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \else
%    \lettonothing\m_font_fallbacks\fi}
%
% \def\font_helpers_set_goodies_yes#name%
%   {\ifcsname\??fontfile\fontclass#name\s!goodies  \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
%    \ifcsname\??fontfile          #name\s!goodies  \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
%    \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \orelse
%    \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \else
%    \lettonothing\m_font_goodies\fi}
%
% \def\font_helpers_set_designsize_yes#name%
%   {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
%    \ifcsname\??fontfile          #name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
%    \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \orelse
%    \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \else
%    \lettonothing\m_font_designsize\fi}
%
% \def\font_helpers_set_features_nop#name%
%   {\ifcsname\??fontfile#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse
%    \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_features_nop\lastnamedcs \else
%    \lettonothing\m_font_features\fi}
%
% \def\font_helpers_set_fallbacks_nop#name%
%   {\ifcsname\??fontfile#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse
%    \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_fallbacks_nop\lastnamedcs \else
%    \lettonothing\m_font_fallbacks\fi}
%
% \def\font_helpers_set_goodies_nop#name%
%   {\ifcsname\??fontfile#name\s!goodies\endcsname \edef\m_font_goodies{\lastnamedcs}\orelse
%    \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_goodies_nop\lastnamedcs \else
%    \lettonothing\m_font_goodies\fi}
%
% \def\font_helpers_set_designsize_nop#name%
%   {\ifcsname\??fontfile#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse
%    \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_designsize_nop\lastnamedcs \else
%    \lettonothing\m_font_designsize\fi}
%
% a bit less tracing:

\def\font_helpers_set_features_yes#name%
  {\ifcsname\??fontfile\fontclass#name\s!features\endcsname  \lettolastnamedcs\m_font_features          \orelse % class + symbolic_name
   \ifcsname\??fontfile          #name\s!features\endcsname  \lettolastnamedcs\m_font_features          \orelse % symbolic_name
   \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \orelse % class + parent_name
   \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \else   % parent_name
   \lettonothing\m_font_features\fi}

\def\font_helpers_set_fallbacks_yes#name%
  {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname \lettolastnamedcs\m_font_fallbacks          \orelse
   \ifcsname\??fontfile          #name\s!fallbacks\endcsname \lettolastnamedcs\m_font_fallbacks          \orelse
   \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \orelse
   \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \else
   \lettonothing\m_font_fallbacks\fi}

\def\font_helpers_set_goodies_yes#name%
  {\ifcsname\??fontfile\fontclass#name\s!goodies  \endcsname \lettolastnamedcs\m_font_goodies          \orelse
   \ifcsname\??fontfile          #name\s!goodies  \endcsname \lettolastnamedcs\m_font_goodies          \orelse
   \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \orelse
   \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \else
   \lettonothing\m_font_goodies\fi}

\def\font_helpers_set_designsize_yes#name%
  {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname\lettolastnamedcs\m_font_designsize          \orelse
   \ifcsname\??fontfile          #name\s!designsize\endcsname\lettolastnamedcs\m_font_designsize          \orelse
   \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \orelse
   \ifcsname\??fontfile          #name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \else
   \lettonothing\m_font_designsize\fi}

\def\font_helpers_set_features_nop#name%
  {\ifcsname\??fontfile#name\s!features\endcsname  \lettolastnamedcs\m_font_features          \orelse
   \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_features_nop\lastnamedcs \else
   \lettonothing\m_font_features\fi}

\def\font_helpers_set_fallbacks_nop#name%
  {\ifcsname\??fontfile#name\s!fallbacks\endcsname \lettolastnamedcs\m_font_fallbacks          \orelse
   \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_fallbacks_nop\lastnamedcs \else
   \lettonothing\m_font_fallbacks\fi}

\def\font_helpers_set_goodies_nop#name%
  {\ifcsname\??fontfile#name\s!goodies\endcsname   \lettolastnamedcs\m_font_goodies          \orelse
   \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_goodies_nop\lastnamedcs \else
   \lettonothing\m_font_goodies\fi}

\def\font_helpers_set_designsize_nop#name%
  {\ifcsname\??fontfile#name\s!designsize\endcsname\lettolastnamedcs\m_font_designsize          \orelse
   \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_designsize_nop\lastnamedcs \else
   \lettonothing\m_font_designsize\fi}

\def\font_helpers_update_font_parameters_yes
  {\font_helpers_set_features_yes  \somefontname
   \font_helpers_set_fallbacks_yes \somefontname
   \font_helpers_set_goodies_yes   \somefontname
   \font_helpers_set_designsize_yes\somefontname}

\def\font_helpers_update_font_parameters_nop
  {\font_helpers_set_features_nop  \somefontname
   \font_helpers_set_fallbacks_nop \somefontname
   \font_helpers_set_goodies_nop   \somefontname
   \font_helpers_set_designsize_nop\somefontname}

\def\font_helpers_update_font_parameters
 {\ifempty\fontclass\font_helpers_update_font_parameters_nop\else\font_helpers_update_font_parameters_yes\fi}

\installcorenamespace{fontclass}

% we can pack them (don't use \setxvalue!)

\permanent\protected\def\savefontclassparameters#style#rscale#features#fallbacks#goodies#designsize%
  {\gletcsname\??fontclass\fontclass#style\s!rscale    \endcsname#rscale%
   \gletcsname\??fontclass\fontclass#style\s!features  \endcsname#features%
   \gletcsname\??fontclass\fontclass#style\s!fallbacks \endcsname#fallbacks%
   \gletcsname\??fontclass\fontclass#style\s!goodies   \endcsname#goodies%
   \gletcsname\??fontclass\fontclass#style\s!designsize\endcsname#designsize}

% bonus

% \currentfontinstancespec % defined at the lua end

\protect \endinput
