#ifndef DRIVER_H
#define DRIVER_H

#include <string.h>
#ifndef NULL
#include <stdlib.h>
#endif

class point {
// position on bi-dimensional panel

	friend class square_pos;
	friend class pc_panel;

	private :
		int ypos, xpos, 				    //position
		    yofst, xofst;	    // ofst for the increment operator

	public :
		point(int y=1, int x=1)
		{ ypos=y; xpos=x; yofst=0; xofst=1; }
		point(int y, int x, const direction &dir);
		point(const point &other)
		{	ypos=other.ypos; xpos=other.xpos;
			yofst=other.yofst; xofst=other.xofst; }
		point &operator=(const point &other)
		{	ypos=other.ypos; xpos=other.xpos;
			yofst=other.yofst; xofst=other.xofst;
			return *this; }
		point(const direction &dir, const point &other);
		void move(const direction &dir, int len=1);
		// increment/decrement y/x positions as implied by direction
		void chg_dir(const direction &dir, int increment=1);
		// modify internal offset for ++ operator
		void chg_dir(int yoffset, int xoffset)
		// modify internal offset for ++ operator
		{ yofst=yoffset; xofst=xoffset; }
		boolean operator==(const point &other)
		{ return(ypos==other.ypos && xpos==other.xpos); }
		boolean operator!=(const point &other)
		{ return(ypos!=other.ypos || xpos!=other.xpos); }
		int y(void) { return(ypos); }
		int x(void) { return(xpos); }
		void sety(int y) { ypos=y; }
		void setx(int x) { xpos=x; }
		point &operator+=(const point &offset);
		// shift by user-specified offset
		point &operator-=(const point &shifted);
		// shift conter to user-specified offset
		point &operator++(void)
		// shift by internally-held offset
		{ ypos+=yofst; xpos+=xofst; return(*this); }
		point &operator--(void)
		// shift counter to internally-held offset
		{ ypos-=yofst; xpos-=xofst; return(*this); }
		char *name(void);
		int how_far(const direction &dir);
};

class square_pos
{ // position measured by pair of extreme corners.

	private :
		point top,	    // up-left corner
		      bot;		// right-down corner
		int curlen, curwd;	// current dimensions

	public :
		square_pos(const point &start, const point &end) {
			top=start; bot=end;
			curlen=bot.ypos-top.ypos+1;
			curwd=bot.xpos-top.xpos+1;
		}
		void set_start(const point &start);
		void set_end(const point &end);
		void set_end_y(int len);
		void set_end_x(int wd);
		void move_limit(const direction &dir, int ofst=1);
		void set_limit(const direction &dir, int pos);
		void move(const direction &dir, int len=1);
		int len(const axis &dim);
		point start(void) { return top; } // (temporary result)
		point end(void) { return bot; } // (temporary result)
		int sty(void) { return top.ypos; }
		int eny(void) { return bot.ypos; }
		int stx(void) { return top.xpos; }
		int enx(void) { return bot.xpos; }
		char *name(void);
};

class pc_panel {
// the screen object

	private :
		square_pos win;
		point cursor;
		int color, def_color;
		int lang;	      // pending language. user-managed values
		point top, bot; 		   // added for efficiency
		int hlen, vlen; 		       // added for efficiency

	public :
		// note: arguments defaulting to NULL are requests from the
		// driver to use (and advance) the built-in cursor.
		// otherwise (arguments supplied) "direct cursor adressing"
		// is requested (and built-in cursor is not affected).

		pc_panel(square_pos *window, int default_clr);
		~pc_panel(void);
		// restores if needed, does not clear!

		char get_c(point *pt=NULL);
		// get char in specified/cursor position
		void put_c(char c, point *pt=NULL);
		// put char in specified/cursor position, using pending color.
		// if cursor position, cursor is advanced one step.
		void put_color(int clr, point *pt=NULL);
		// set color in specified/cursor position
		int get_color(point *pt=NULL);
		// retrieve color in specified/cursor position
		void posit(point *pt=NULL);
		// reposition to specified/internal-cursor position
		void save(void);
		// save whole window content (not stackable!)
		void restore(void);
		// restore window to state of last save operation, delete buff
		unsigned int ask_cursor(void);
		// user-managed values
		void set_cursor(unsigned int cursor_type);
		// user-managed values
		unsigned int hide_cursor(void);
		// retruns current shape
		void fix(void);
		// fix controlled data redundancy

		boolean ask_legal(point *pt);
		// tell if point is within window range
		boolean next(point *pt=NULL);
		// move cursor/specified-point one position, if possible
		char next_c(point *pt=NULL);
		// get neighbour of cursor/specified char
		void clr_eol(point *pt=NULL);
		// clear from specified/cursor position to end-of-line
		void clear(void);
		// clear whole screen and posit home
		void put_s(char *s, point *pt=NULL);
		// write a string on screen starting at cursor/specified point.
		// if cursor, it  is advanced.
		void home(void);
		// position to start corner of screen.
xx		int ask_limit(boolean );
		// beginning/end of window - height/breadth
		void set_limit(const &dir, int pos);
		// modify window dimensions
		void move_limit(const &dir, int ofst=1);
		// modify window dimensions, relative

		void arclist(point *pt, int len, const &dir,
		 const weight_d &wgt, boolean tipped=FALSE, int *clr=NULL);
		// draw straight line from y:x in length specified
		void arcclr(point *pt, int len, const &dir);
		// clear space formerly occupied by arc

		// management
		void set_color(intnew_color);
		int ask_color(void);
		int ask_def_color(void);
		void toggle_attr(vd_attr at);
		void reset_color(void);
		void set_def_color(intclr);
		point ask_where(void) { return cursor; }
		ask_dir(void) { return curdir; }
		int ask_len(const axis &dim);
		point ask_corner(const &dir);
		// current screen window corner - either top-left or bot-right
		square_pos ask_window(void);

		// misc
		boolean enframe(const weight_d &wgt=h1v1, char *title="\0",
		 boolean centered=FALSE);
		// draw oblong around pc_panel and contract
		void deframe(void);
		// expand (checks nothing)
} ;

