/*
* console.h
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/

#ifndef _CONSOLE

#define _CONSOLE

#define RED console::red
#define GREEN console::green
#define YELLOW console::yellow
#define CYAN console::cyan
#define tab "  "
#define eol console::EOL << YELLOW

#include "dingl.h"
#include "globals.h"
#include "color.h"
#include <list>
#include <vector>
#include <string>
#include <sstream>

#include "arrow_button.h"

struct mesg {
  std::string text; // text
  color clr; // color
  mesg (const std::string& t, const color& c) : text(t), clr(c) {}
  mesg (const std::string& t) : text(t), clr (1, 1, 1) {}
  mesg () : text (""), clr (1, 1, 1) {}
};

typedef std::list<mesg>::iterator line_iterator;

struct console : widget, pusher<console>, click_listener {

  int maxlines;

  // colors of text (defined in main.cc)
  static const color yellow;
  static const color green;
  static const color red;
  static const color cyan;
	static const color white;

  static const char EOL = '\n'; // end of last mesg
  static const char CLL = '\b'; // clear last mesg
  static const char* precision; // for printing float, double values

  // console text is a bunch of lines
  static const int GUTTER = 7; 
  int nlines; // number of lines in console
  int lines_per_screen; 
  int startl;
  line_iterator it_startl;
  void calc_startl_iterator ();
  std::list<mesg> lines;
  void add_line (const mesg& ln);
  void clear (); 
  mesg cur_line; // currently edited line
  color clr; // its color

  console ();
  ~console ();

  console& operator() (const std::string& cmd); // run DIN command

  // operators for appending values to console
  console& operator<< (unsigned int i);
  console& operator<< (unsigned long i);
  console& operator<< (unsigned long long i);
  console& operator<< (int i);
  console& operator<< (const std::string& s);
  console& operator<< (float f);
  console& operator<< (double d);
  console& operator<< (char c);
  console& operator<< (const color& d);
	
  /*
  int suppress; // suppress line add
  console& operator-- () { suppress = 1; return *this; } // console closed, no more lines can be added
	console& operator++ () { suppress = 0; return *this; } // console opened 
  */

  void up (int i); // scroll up by i lines
  void down (int i); // scroll down
  void pgdn (); // page down
  void pgup (); // page up
  void home (); // scroll to show 1st line
  void end (); // scroll to show last line
  void last (); // ensures last mesg is always displayed
  void del (); // del one character from currently edited line

  // visual
  //
  arrow_button b_roll; // button to roll/unroll console
  int rollup_; // show last line only?
  int last_rollup_; 
  void rollup (int r);
  int rollup () {return rollup_;}

  int char_width;
  box<int> win;
  void set_window (const box<int>& w);
  int startx, starty; 
  int curs_loc;
  int curs_locx;
  void calc_visual_params ();
  void draw ();

  int handle_input ();
  void clicked (button& b);

  // commands
  int command_mode;
  mesg cmd_line;
	void clear_cmd_line ();
	void set_cmd_line (const std::string& s, const color& c = white);
  void toggle_command_mode ();

  std::vector<std::string> history; // command history
  int hid;

};

extern const char spc;

template <class T> inline console& operator<< (console& c, const box<T>& b) {
  c << b.left << spc << b.bottom << spc << b.right << spc << b.top << spc << b.width << spc << b.height;
  return c;
}

template <class T> inline console& operator<< (console& c, const point<T>& p) {
	c << p.x << spc << p.y;
	return c;
}

extern console cons;

#endif
