% --------------------------------------------------------------------------
% the EXSHEETS package
% 
%   Yet another package for the creation of exercise sheets
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/exsheets/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2011-2012 Clemens Niederberger
% 
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% The exsheets package consists of the files
%  - exsheets.sty, exsheets_headings.def, exsheets_headings.cfg,
%    exsheets_tasks.def, exsheets_tasks.cfg, exsheets_configurations.cfg,
%  - exsheets_en.tex, exsheets_en.pdf,
%  - README
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
% TASKS: LIST-LIKE ENVIRONMENT
\ProvidesFile{exsheets_tasks.def}
  [\exsheets@date\space v\exsheets@version\space ExSheets tasks object]

\RequirePackage { epic }

% variables:
\seq_new:N    \l__exsheets_tasks_seq
\int_new:N    \l__exsheets_tasks_depth_int
\int_new:N    \g__exsheets_tasks_int
\int_new:N    \l__exsheets_tasks_total_items_int
\int_new:N    \l__exsheets_tasks_columns_int
\int_new:N    \l__exsheets_tasks_rows_int
\bool_new:N   \l__exsheets_tasks_enumerate_bool
\bool_new:N   \l__exsheets_tasks_resume_bool
\tl_new:N     \l__exsheets_tasks_instance_tl
\tl_new:N     \l__exsheets_tasks_label_tl
\tl_new:N     \l__exsheets_tasks_label_pattern_tl
\tl_new:N     \l__exsheets_tasks_custom_label_format_tl
\dim_new:N    \l__exsheets_tasks_item_indent_dim
\dim_new:N    \l__exsheets_tasks_item_width_dim
\dim_new:N    \l__exsheets_tasks_label_width_dim
\dim_new:N    \l__exsheets_tasks_default_label_width_dim
\skip_new:N   \l__exsheets_tasks_after_item_skip
\skip_new:N   \l__exsheets_tasks_before_list_skip
\skip_new:N   \l__exsheets_tasks_after_list_skip

\NewCounterPattern* [ exsheets ] { task } { tsk }
\ReadCounterFrom [ exsheets ] { task } \g__exsheets_tasks_int

% scratch coffins:
\cs_if_exist:NF \l__exsheets_tmpa_coffin { \coffin_new:N \l__exsheets_tmpa_coffin }
\cs_if_exist:NF \l__exsheets_tmpb_coffin { \coffin_new:N \l__exsheets_tmpb_coffin }
\cs_if_exist:NF \l__exsheets_tmpc_coffin { \coffin_new:N \l__exsheets_tmpc_coffin }

% collect the tasks:
\cs_new:Npn \__exsheets_collect_tasks:nw #1#2 \end #3
  {
    \tl_put_right:Nn \l__exsheets_tasks_body_tl { #1 }
    \end { #3 }
    \tl_if_eq:nnF { #1 } { #3 }
      { \__exsheets_collect_tasks:nw { #1 } }
  }

%  #1: instance
%  #2: number of columns
%  #3: item separator
%  #4: environment body
\cs_new:Npn \__exsheets_tasks:nnnn #1#2#3#4
  {
    \seq_set_split:Nnn \l__exsheets_tasks_seq { #3 } { #4 }
    % remove the first (empty) item:
    \seq_pop_left:NN \l__exsheets_tasks_seq \l__exsheets_tmpa_tl
    \tl_if_blank:VF \l__exsheets_tmpa_tl
      { \tl_show:N \l__exsheets_tmpa_tl \@noitemerr }
    \int_set:Nn \l__exsheets_tasks_total_items_int
      { \seq_length:N \l__exsheets_tasks_seq }
    \UseInstance { exsheets-tasks } { #1 }
      { \l__exsheets_tasks_total_items_int }
      { #2 }
      { \l__exsheets_tasks_custom_label_format_tl }
    % just to be sure:
    \seq_clear:N \l__exsheets_tasks_seq
  }
\cs_generate_variant:Nn \__exsheets_tasks:nnnn { VnnV }

\cs_new:Npn \__exsheets_task:nnw #1#2[#3,#4][#5,#6](#7,#8)
  {
    \dim_set:Nn \l__exsheets_tasks_item_width_dim
      {
        \linewidth / \l__exsheets_tasks_columns_int -
        \l__exsheets_tasks_depth_int \l__exsheets_tasks_item_indent_dim
      }
    \int_incr:N \l__exsheets_tmpa_int
    \__exsheets_tasks_set_rows_num:NN
      \l__exsheets_tasks_total_items_int
      \l__exsheets_tasks_columns_int
    \int_compare:nT { \l__exsheets_tmpa_int > \l__exsheets_tasks_columns_int }
      { \int_set:Nn \l__exsheets_tmpa_int { 1 } }
    % the item:
    \hcoffin_set:Nn \l__exsheets_tmpa_coffin
      {
        \vcoffin_set:Nnn \l__exsheets_tmpc_coffin
          { \l__exsheets_tasks_item_width_dim }
          { \__exsheets_tasks_setup: #2 }
        \coffin_typeset:Nnnnn \l__exsheets_tmpc_coffin
          { l } { T } { 0pt } { 0pt }
      }
    % the label:
    \hcoffin_set:Nn \l__exsheets_tmpb_coffin { \strut #1 }
    \coffin_attach:NnnNnnnn
      \l__exsheets_tmpa_coffin { l } { T }
      \l__exsheets_tmpb_coffin { l } { T } { -\l__exsheets_tasks_label_width_dim } { 0pt }
    % typeset label & item:
    % need this when a new row starts:
    \int_compare:nT { \l__exsheets_tmpa_int = 1 }
      { \skip_vertical:N \c_zero_skip }
    \skip_horizontal:N \l__exsheets_tasks_item_indent_dim
    \coffin_typeset:Nnnnn \l__exsheets_tmpa_coffin { l } { T } { 0pt } { 0pt }
    % need this before a new row starts:
    \int_compare:nT { \l__exsheets_tmpa_int = \l__exsheets_tasks_columns_int }
      { \skip_vertical:N \l__exsheets_tasks_after_item_skip }
    \coffin_clear:N \l__exsheets_tmpa_coffin
    \coffin_clear:N \l__exsheets_tmpb_coffin
    \coffin_clear:N \l__exsheets_tmpc_coffin
  }
\cs_generate_variant:Nn \__exsheets_task:nnw { VV }

\cs_new:Npn \__exsheets_tasks_setup:
  {
    \dim_set:Nn \parskip { 0pt }
    \skip_set:Nn \parfillskip { 0pt plus 1fil }
    \dim_set_eq:NN \parskip \parsep
    \dim_set_eq:NN \parindent \listparindent
    \strut
  }

\cs_new:Npn \__exsheets_tasks_set_rows_num:NN #1#2
  {
    \int_set:Nn \l__exsheets_tasks_rows_int { \int_div_truncate:nn { #1 } { #2 } }
    \int_compare:nNnT { \int_mod:nn { #1 } { #2 } } > { 0 }
      { \int_incr:N \l__exsheets_tasks_rows_int }
  }

% the `exsheets-tasks' object:
%   #1: number of items
%   #2: number of columns
%   #3: label-format
\DeclareObjectType { exsheets-tasks } { 3 }
% the `default' template interface:
\DeclareTemplateInterface { exsheets-tasks } { default } { 3 }
  {
    enumerate       : boolean   = true    ,
    label           : tokenlist           ,
    indent          : length    = 2.5em   ,
    label-format    : tokenlist = tsk[a]) ,
    label-width     : length    = 3ex     ,
    after-item-skip : skip      = 1ex plus 1ex minus 1ex
  }
% the `default' template code:
\DeclareTemplateCode { exsheets-tasks } { default } { 3 }
  {
    enumerate       = \l__exsheets_tasks_enumerate_bool          ,
    label           = \l__exsheets_tasks_label_tl                ,
    indent          = \l__exsheets_tasks_item_indent_dim         ,
    label-format    = \l__exsheets_tasks_label_pattern_tl         ,
    label-width     = \l__exsheets_tasks_default_label_width_dim ,
    after-item-skip = \l__exsheets_tasks_after_item_skip
  }
  {
    \AssignTemplateKeys
    \dim_compare:nT { \l__exsheets_tasks_label_width_dim = 0pt }
      {
        \dim_set_eq:NN
          \l__exsheets_tasks_label_width_dim
          \l__exsheets_tasks_default_label_width_dim
      }
    % need this for enumerate list:
    \bool_if:nT { !\l__exsheets_tasks_resume_bool && \l__exsheets_tasks_enumerate_bool }
      { \int_gzero:N \g__exsheets_tasks_int }
    \int_set:Nn \l__exsheets_tasks_columns_int { #2 }
    % set all the items in their own coffins and join with the ground:
    \int_zero:N \l__exsheets_tmpa_int
    \tl_if_blank:VF \l__exsheets_tasks_custom_label_format_tl
      {
        \tl_set_eq:NN
          \l__exsheets_tasks_label_pattern_tl
          \l__exsheets_tasks_custom_label_format_tl
      }
    \seq_map_inline:Nn \l__exsheets_tasks_seq
      {
        \__exsheets_read_item:w ##1 \q_stop
        \bool_if:NTF \l__exsheets_tasks_enumerate_bool
          {
            \int_gincr:N \g__exsheets_tasks_int
            \tl_if_blank:VT \l__exsheets_tasks_label_tl
              {
                \tl_set:Nn \l__exsheets_tasks_label_tl
                  {
                    \ReadCounterPatternFrom [ exsheets ]
                      \l__exsheets_tasks_label_pattern_tl
                  }
              }
          }
          {
            \tl_if_blank:VT \l__exsheets_tasks_label_tl
              { \tl_set_eq:NN \l__exsheets_tasks_label_tl \labelitemi }
          }
        \tl_if_blank:VTF \l__exsheets_tasks_tmp_label_tl
          {
            \__exsheets_task:VVw
              \l__exsheets_tasks_label_tl
              \l__exsheets_tasks_item_tl
              [ l , b ] [ l , t ] ( 0pt , 0pt )
          }
          {
            \__exsheets_task:VVw
              \l__exsheets_tasks_tmp_label_tl
              \l__exsheets_tasks_item_tl
              [ l , b ] [ l , t ] ( 0pt , 0pt )
            \tl_clear:N \l__exsheets_tasks_tmp_label_tl
          }
      }
  }

\tl_new:N \task
\tl_new:N \l__exsheets_tasks_item_tl
\tl_new:N \l__exsheets_tasks_tmp_label_tl

\cs_new:Npn \__exsheets_read_item:w
  {
    \peek_meaning:NTF [
      { \__exsheets_read_item_aux:w }
      { \__exsheets_read_item_aux:w[] }
  }

\cs_new:Npn \__exsheets_read_item_aux:w [#1]#2 \q_stop
  {
    \tl_if_blank:nF { #1 }
      { \tl_set:Nn \l__exsheets_tasks_tmp_label_tl { #1 } }
    \tl_set:Nn \l__exsheets_tasks_item_tl { \ignorespaces #2 }
  }

% choice box:
\bool_new:N \l__exsheets_choice_checked_bool
\dim_new:N  \l__exsheets_choice_width_dim
\dim_set:Nn \l__exsheets_choice_width_dim { 1.25ex }
\dim_new:N  \l__exsheets_choice_linewidth_dim
\dim_set:Nn \l__exsheets_choice_linewidth_dim { .3pt }
\dim_new:N  \l__exsheets_choice_checkwidth_dim
\dim_set:Nn \l__exsheets_choice_checkwidth_dim { .5pt }
\dim_new:N  \l__exsheets_choice_raise_dim
\dim_set:Nn \l__exsheets_choice_raise_dim { .1ex }

\cs_new:Npn \exsheets_choice:
  {
    \leavevmode
    \bool_set_false:N \l__exsheets_choice_checked_bool
    \box_move_up:nn
      { \l__exsheets_choice_raise_dim }
      { \hbox:n { \__exsheets_choice: } }
  }

\cs_new:Npn \exsheets_choice_checked:
  {
    \leavevmode
    \bool_set_true:N \l__exsheets_choice_checked_bool
    \box_move_up:nn
      { \l__exsheets_choice_raise_dim }
      { \hbox:n { \__exsheets_choice: } }
  }

\cs_new:Npn \__exsheets_choice:
  {%
    \dim_set:Nn \unitlength { .1\l__exsheets_choice_width_dim }
    \begin{picture}(10,0)
      \linethickness \l__exsheets_choice_linewidth_dim
      \drawline(0,0)(0,10)(10,10)(10,0)(0,0)
      \linethickness \l__exsheets_choice_checkwidth_dim
      \bool_if:NT \l__exsheets_choice_checked_bool
        {
          \drawline(2,2)(8,8)
          \drawline(2,8)(8,2)
        }
    \end{picture}%
  }

\providecommand* \choicebox { \exsheets_choice: }
\providecommand* \checkedchoicebox { \exsheets_choice_checked: }

% base instance:
% ALPHABETIZE: a) b) c)
\DeclareInstance { exsheets-tasks } { alphabetize } { default } { }

\keys_define:nn { exsheets / tasks }
  {
    style       .tl_set:N   = \l__exsheets_tasks_instance_tl ,
    label       .tl_set:N   = \l__exsheets_tasks_custom_label_format_tl ,
    label-width .dim_set:N  = \l__exsheets_tasks_label_width_dim ,
    before-skip .skip_set:N = \l__exsheets_tasks_before_list_skip ,
    after-skip  .skip_set:N = \l__exsheets_tasks_after_list_skip ,
    resume      .bool_set:N = \l__exsheets_tasks_resume_bool
  }

% the generic environment:
\NewEnviron { __exsheets_tasks_env: } [ 3 ]
  {
    \keys_set:nn { exsheets / tasks } { #2 }
    \tl_if_blank:VT \l__exsheets_tasks_instance_tl
      { \keys_set:nn { exsheets / tasks } { style = alphabetize } }
    \skip_vertical:N \l__exsheets_tasks_before_list_skip
    \skip_vertical:N \c_zero_skip
    \list {}
      {
        \dim_set:Nn \leftmargin { 0pt }
        \dim_set:Nn \rightmargin { 0pt }
      }
    \item \scan_stop:
    \int_incr:N \l__exsheets_tasks_depth_int
    \__exsheets_tasks:VnnV \l__exsheets_tasks_instance_tl { #3 } { #1 } \BODY
    \endlist
    \skip_vertical:N \l__exsheets_tasks_after_list_skip
  }

% the user environment:
\NewDocumentCommand \NewTasks { O{}mO{\task}D(){1} }
  {
    \NewDocumentEnvironment { #2 } { O{}G{#4} }
      { \__exsheets_tasks_env: { #3 } { #1,##1 } { ##2 } }
      { \end__exsheets_tasks_env: }
  }

\NewDocumentCommand \RenewTasks { O{}mO{\task}D(){1} }
  {
    \RenewDocumentEnvironment { #2 } { O{}G{#4} }
      { \__exsheets_tasks_env: { #3 } { #1,##1 } { ##2 } }
      { \end__exsheets_tasks_env: }
  }

\NewTasks { tasks }

\tex_endinput:D
% TODO: option für after-item-skip