/Users/gre462/Documents/MOOSE/projects/moose/framework/include/utils/FormattedTable.h
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#ifndef FORMATTEDTABLE_H
#define FORMATTEDTABLE_H
// MOOSE includes
#include "Moose.h"
#include "MooseEnum.h"
#include "DataIO.h"
// C++ includes
#include <fstream>
// Forward declarations
class FormattedTable;
namespace libMesh
{
class ExodusII_IO;
}
template <>
void dataStore(std::ostream & stream, FormattedTable & table, void * context);
template <>
void dataLoad(std::istream & stream, FormattedTable & v, void * context);
/**
 * This class is used for building, formatting, and outputting tables of numbers.
 */
class FormattedTable
{
public:
  /**
   * Default constructor - The default constructor takes an optional parameter to turn off
   * stateful printing. This means that each time you ask the FormattedTable to print to a file,
   * it'll, print the entire table. The default is to only print the part of the table that hasn't
   * already been printed.
   */
  FormattedTable();
  /**
   * Copy constructor - The copy constructor will duplicate the data structures but is not
   * designed to work with FormattedTables with open streams (e.g. CSV Output mode).
   */
  FormattedTable(const FormattedTable & o);
  /**
   * The destructor is used to close the file handle
   */
  ~FormattedTable();
  /**
   * Returns a boolean value based on whether the FormattedTable contains data or not
   */
  bool empty() const;
  /**
   * Sets append mode which means an existing file is not truncated on opening. This mode
   * is typically used for recovery.
   */
  void append(bool append_existing_file);
  /**
   * Force a new row in the table with the passed in time.
   */
  void addRow(Real time);
  /**
   * Method for adding data to the output table. Data is added to the last row. Method will
   * error if called on an empty table.
   */
  void addData(const std::string & name, Real value);
  /**
   * Method for adding data to the output table.  The dependent variable is named "time"
   */
  void addData(const std::string & name, Real value, Real time);
  /**
   * Method for adding an entire vector to a table at a time. Checks are made to ensure that
   * the dependent variable index lines up with the vector indices.
   */
  void addData(const std::string & name, const std::vector<Real> & vector);
  /**
   * Retrieve the last time (or independent variable) value.
   */
  Real getLastTime();
  /**
   * Retrieve Data for last value of given name
   */
  Real & getLastData(const std::string & name);
  void clear();
  /**
   * Set whether or not to output time column.
   */
  void outputTimeColumn(bool output_time) { _output_time = output_time; }
  //  const std::map<Real, std::map<std::string, Real>> & getData() const { return _data; }
  /**
   * Methods for dumping the table to the stream - either by filename or by stream handle.  If
   * a filename is supplied opening and closing of the file is properly handled.  In the
   * screen version of the method, an optional parameters can be passed to print only the last
   * "n" entries.  A value of zero means don't skip any rows
   *
   * Note: Only call these from processor 0!
   */
  void printTable(std::ostream & out, unsigned int last_n_entries = 0);
  void printTable(std::ostream & out,
                  unsigned int last_n_entries,
                  const MooseEnum & suggested_term_width);
  void printTable(const std::string & file_name);
  /**
   * Method for dumping the table to a csv file - opening and closing the file handle is handled
   *
   * Note: Only call this on processor 0!
   */
  void printCSV(const std::string & file_name, int interval = 1, bool align = false);
  void printEnsight(const std::string & file_name);
  void writeExodus(ExodusII_IO * ex_out, Real time);
  void makeGnuplot(const std::string & base_file, const std::string & format);
  static MooseEnum getWidthModes();
  /**
   * By default printCSV places "," between each entry, this allows this to be changed
   */
  void setDelimiter(std::string delimiter) { _csv_delimiter = delimiter; }
  /**
   * By default printCSV prints output to a precision of 14, this allows this to be changed
   */
  void setPrecision(unsigned int precision) { _csv_precision = precision; }
  /**
   * Sorts columns alphabetically.
   */
  void sortColumns();
protected:
  void printTablePiece(std::ostream & out,
                       unsigned int last_n_entries,
                       std::map<std::string, unsigned short> & col_widths,
                       std::vector<std::string>::iterator & col_begin,
                       std::vector<std::string>::iterator & col_end);
  void printOmittedRow(std::ostream & out,
                       std::map<std::string, unsigned short> & col_widths,
                       std::vector<std::string>::iterator & col_begin,
                       std::vector<std::string>::iterator & col_end) const;
  void printRowDivider(std::ostream & out,
                       std::map<std::string, unsigned short> & col_widths,
                       std::vector<std::string>::iterator & col_begin,
                       std::vector<std::string>::iterator & col_end) const;
  void printNoDataRow(char intersect_char,
                      char fill_char,
                      std::ostream & out,
                      std::map<std::string, unsigned short> & col_widths,
                      std::vector<std::string>::iterator & col_begin,
                      std::vector<std::string>::iterator & col_end) const;
  /**
   * Returns the width of the terminal using sys/ioctl
   */
  unsigned short getTermWidth(bool use_environment) const;
  /**
   * Data structure for the console table:
   * The first part of the pair tracks the independent variable (normally time) and is associated
   * with the second part of the table which is the map of dependent variables and their associated
   * values.
   */
  std::vector<std::pair<Real, std::map<std::string, Real>>> _data;
  /// Alignment widths (only used if asked to print aligned to CSV output)
  std::map<std::string, unsigned int> _align_widths;
  /// The set of column names updated when data is inserted through the setter methods
  std::vector<std::string> _column_names;
  /// The single cell width used for all columns in the table
  static const unsigned short _column_width;
  /// The absolute minimum PPS table width
  static const unsigned short _min_pps_width;
private:
  /// Close the underlying output file stream if any. This is idempotent.
  void close();
  /// Open or switch the underlying file stream to point to file_name. This is idempotent.
  void open(const std::string & file_name);
  void printRow(std::pair<Real, std::map<std::string, Real>> & row_data, bool align);
  /// The optional output file stream
  std::string _output_file_name;
  /// The stream handle (corresponds to _output_file_name)
  std::ofstream _output_file;
  /**
   * Keeps track of the index indicating which vector elements have been output. All items
   * with an index less than this index have been output. Higher values have not.
   */
  std::size_t _output_row_index;
  /**
   * Keeps track of whether the header has been output. This is separate from _output_row_index
   * because it's possible to output the header with zero rows. We don't consider this a bug,
   * it helps users understand that they have declared vectors properly but maybe haven't populated
   * them correctly.
   */
  bool _headers_output;
  /// Keeps track of whether we want to open an existing file for appending or overwriting.
  bool _append;
  /// Whether or not to output the Time column
  bool _output_time;
  /// *.csv file delimiter, defaults to ","
  std::string _csv_delimiter;
  /// *.csv file precision, defaults to 14
  unsigned int _csv_precision;
  /// Flag indicating that sorting is necessary (used by sortColumns method).
  bool _column_names_unsorted = true;
  friend void
  dataStore<FormattedTable>(std::ostream & stream, FormattedTable & table, void * context);
  friend void dataLoad<FormattedTable>(std::istream & stream, FormattedTable & v, void * context);
};
template <>
void dataStore(std::ostream & stream, FormattedTable & table, void * context);
template <>
void dataLoad(std::istream & stream, FormattedTable & v, void * context);
#endif // FORMATTEDTABLE_H