//////////////////////////////////////////////////////////////////////////////////
//
// print, pprint, and tostring
//
// This module implements the heart of the lua 'print', lua 'pprint', and lua
// 'tostring' functions. Note that we have to override the lua builtins 'print'
// and 'tostring' for two reasons:
//
//   * We need to suppress the printing of table addresses, for determinism.
//   * We need to channel the output to a PrintBuffer in the world model.
//
// Note that the actual lua 'print' and 'pprint' routines aren't defined in this
// module, they're in the World module, because they send their output into the
// PrintBuffer of the world model.  But all the tricky code to implement 'print'
// and 'pprint' are in this module.
//
//////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "luastack.hpp"
#include <ostream>

class PrettyPrint {
    bool atomic_;
    bool quote_;
    bool indent_;
    int level_;
    bool expand_;
    PrettyPrint(bool atomic, bool quote, bool indent, int level, bool expand)
        : atomic_(atomic), quote_(quote), indent_(indent), level_(level), expand_(expand) {}
public:
    // PrettyPrint that pretty-prints and indents and
    // expands top-level tables.  This is probably the
    // default you want for most things.
    //
    static PrettyPrint Indented() { return {false, false, true, 0, true}; }
    
    // PrettyPrint that pretty-prints, you can specify
    // whether it indents and whether it expands top-level
    // tables.
    //
    static PrettyPrint Pretty(bool indent, bool expand) { return {false, false, indent, 0, expand}; }

    // PrettyPrint that prints something atomically, not
    // showing the contents of tables.  You can specify
    // whether strings are to be quoted or not.
    //
    static PrettyPrint Atomic(bool quote) { return {true, quote, true, 0, true}; }

    // Print a single value in the specified style.
    //
    void print(LuaCoreStack &LS, LuaSlot val, std::ostream *os) const;

    // Format a string using printf-style format specifiers, consuming
    // arguments from a LuaExtraArgs.  Returns an empty string on success,
    // or an error message on failure.  Errors mainly consist of
    // invalid format strings or incorrect arguments for the format
    // string.
    //
    // Numeric types (argument must be a number).  All of the following
    // use the same formatting parameters as 'printf'.
    //
    //   %d, %i   — signed decimal integer
    //   %o       — unsigned octal
    //   %u       — unsigned decimal
    //   %x, %X   — unsigned hexadecimal (lower/upper)
    //   %e, %E   — scientific notation (lower/upper)
    //   %f       — decimal floating point
    //   %g, %G   — shortest of %e/%f (lower/upper)
    //   %c       — character (integer converted to character)
    //
    // Non-numeric types:
    //   %s       — prints any lua value using atomic_print (unquoted)
    //   %q       — prints any lua value using atomic_print (quoted)
    //
    // Pretty-printing:
    //
    //   %p       - pretty print
    //   %lp      - pretty print, but all on one line
    //   %P       - pretty print, force table expansion
    //   %lP      - pretty print, force table expansion, all on one line
    //
    // Special:
    //   %%       — literal percent sign (consumes no argument)
    //
    static eng::string format(LuaCoreStack &LS, std::string_view fmt, LuaExtraArgs args, std::ostream *os);

    friend class PrintMachine;
};
