/* pk-table.pk - Output tabulated data to the terminal.  */

/* `Because tabs SUCK ass', Poke version.  */

/* Copyright (C) 2022, 2023 Jose E. Marchesi */

/* This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

type Pk_Table_Entry =
  struct
  {
    string style;
    string hyperlink;
    string str;
  };

type Pk_Table_Row =
  struct
  {
    string style;
    Pk_Table_Entry[] entries;
  };

type Pk_Table =
 struct
 {
   fun pk_table_default_printer = (string s) void:
   {
     print (s);
   }

   int<32> num_columns;
   int<32> next_column_index;
   int<32> indent;
   int<32> max_column_size;
   int<32>[num_columns] column_widths;
   Pk_Table_Row[] rows;
   (string)void printer = pk_table_default_printer;

   method row = (string style = "") void:
   {
     /* Make sure the current row is complete.  */
     assert (rows'length == 0
             || next_column_index == num_columns);

     rows += [Pk_Table_Row { style = style }];
     next_column_index = 0;
   }

   method column = (string str, string style = "",
                    string hyperlink = "") void:
   {
     var row = rows[rows'length - 1];

     row.entries += [Pk_Table_Entry { style = style,
                                      hyperlink = hyperlink,
                                      str = str }];
     next_column_index += 1;
   }

   method print_table = void:
   {
     /* Calculate the column widths.  */
     for (var i = 0; i < num_columns; ++i)
     {
       var cwidth = 0;

       for (row in rows)
       {
         var entry_width = row.entries[i].str'length + 2;
         if (entry_width > cwidth)
           cwidth = entry_width;
       }

       column_widths[i] = cwidth;
     }

     /* Now print out the stuff.  */
     for (row in rows)
     {
       if (row.style != "")
         term_begin_class (row.style);

       var j = 0;
       for (entry in row.entries)
       {
         if (entry.style != "" && printer == pk_table_default_printer)
           term_begin_class (entry.style);
         if (entry.hyperlink != "" && printer == pk_table_default_printer)
           term_begin_hyperlink (entry.hyperlink);

         printer (" " * indent);
         if (max_column_size == 0 || entry.str'length < max_column_size)
           printer (entry.str);
         else
           for (var i = 0; i < max_column_size; ++i)
             printer (entry.str[i] as string);

         if (entry.hyperlink != "" && printer == pk_table_default_printer)
           term_end_hyperlink;
         if (entry.style != "" && printer == pk_table_default_printer)
           term_end_class (entry.style);

         if (j < row.entries'length - 1)
         {
           var fill = column_widths[j++] - entry.str'length + 1;
           printer (" " * fill);
         }
       }

       if (row.style != "" && printer == pk_table_default_printer)
         term_end_class (row.style);

       printer ("\n");
     }
   }
 };
