// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

//  surface class

#ifndef SURFACEH
#define SURFACEH

#include <config.h>
#include <gf.h>
#include <DREstring.h>

#include <iostream.h>
#include <stdio.h>

// the int entry for clr in the following classes represents the entry number
// in the surface colourmap

extern const char* PORTRAIT,
                 * LANDSCAPE;

const int initial_canvas_height = 480,
          initial_canvas_width = 671;

const char ESC = (char)27;

class Circle
{ int _x, _y, _r, _clr;

public:
  Circle(const int, const int, const int, const int = -1);

  reveal(int, x, _x);
  reveal(int, y, _y);
  reveal(int, r, _r);
  reveal(int, clr, _clr);
};

class text
{ int _x, _y, _height, _clr;
  DREstring _words;
  
public:
  text(const int, const int, const int, DREstring, const int = -1);

  reveal(int, x, _x);
  reveal(int, y, _y);
  reveal(int, height, _height);
  reveal(int, clr, _clr);
  reveal(DREstring, words, _words);
  reveal(int, length, _words.length());
};

class dot
{ int _x, _y, _size, _clr;

public:
  dot(const int, const int, const int = 1, const int = -1);
  dot(const dot&);
  boolean operator==(const dot&) const;
  inline boolean operator!=(const dot& d) const
    { return !(*this == d); }
  void operator=(const dot&);     

  reveal(int, x, _x);
  reveal(int, y, _y);
  reveal(int, size, _size);
  reveal(int, clr, _clr);
};

class LINE
{ int _x1, _y1, _x2, _y2, _clr;

public:
  LINE(const int, const int, const int, const int, const int = -1);

  reveal(int, x1, _x1);
  reveal(int, y1, _y1);
  reveal(int, x2, _x2);
  reveal(int, y2, _y2);
  reveal(int, clr, _clr);
};

class box
{ int _x1, _y1, _x2, _y2, _clr;

public:
  box(const int, const int, const int, const int, const int = -1);

  reveal(int, x1, _x1);
  reveal(int, y1, _y1);
  reveal(int, x2, _x2);
  reveal(int, y2, _y2);
  reveal(int, clr, _clr);
};

// surface is an ABC
class surface
{
  
  // the "use" area is that part of the surface which can be drawn on;
  // the "im" area is that portion which holds the central image, not
  // including the axes, title, &c.
  
protected:
  grey_font* gfp;
  int use_top, use_bottom, use_left, use_right, x_ofs, 
      y_ofs, font_height, im_top, im_bottom, im_left, im_right, _dotsize;
  DREstring font;
  
  void _dump_to_none(void) { }

  typedef void (surface::*PMFV)(void);
  PMFV _dump_to_printer;

public:
  surface(void);
  virtual ~surface(void) { }
  virtual surface& operator<<(LINE&) = 0;
  surface& operator<<(box&);
  surface& operator<<(Circle&);
  virtual surface& operator<<(dot&) = 0;
  virtual surface& operator<<(text&) = 0; 
  virtual surface& resize_usable(int x0 = -1, int y0 = -1, int x1 = -1,
                                 int y1 = -1, int ofsx = -1, int ofsy = -1);
  virtual surface& operator<<(grey_font&) { return *this; };

  virtual void flush(void) = 0;

  virtual void moveto(const int x, const int y) = 0;

  virtual void moverel(const int x, const int y)
    { cerr << "surface::moverel(int, int) called\n"; }

  virtual int resize_font(const int width, const int height)
    { return gfp->resize(width, height); }
  inline int max_character_number(const int width, const int height)
    { return gfp->max_character_number(width, height); }
  inline void operator+=(const int n)
    { *gfp += n; }

  virtual void print(void)
    { (this->*_dump_to_printer)(); }

  inline int image_top(void) { return im_top; }
  inline int image_bottom(void) { return im_bottom; }
  inline int image_height(void) { return abs(im_bottom - im_top) + 1; }
  inline int image_left(void) { return im_left; }
  inline int image_right(void) { return im_right; }
  inline int image_width(void) { return abs(im_right - im_left) + 1; }
  
  inline virtual int usable_top(void) 
    { return use_top; }
  inline virtual int usable_bottom(void) 
    { return use_bottom; }
  inline virtual int usable_height(void) 
    { return abs(usable_bottom() - usable_top()) + 1; }
  inline virtual int usable_left(void) 
    { return use_left; }
  inline virtual int usable_right(void) 
    { return use_right; }
  inline virtual int usable_width(void) 
    { return abs(usable_right() - usable_left()) + 1; }
  inline void dotsize(int n) 
    { _dotsize = n; }
  inline int dotsize(void) 
    { return _dotsize; }

  void set_image(const int, const int, const int, const int);
  virtual int width(void) = 0;
  virtual int height(void) = 0;
  virtual void clear(void) = 0;
  virtual void invert(void) {};
  virtual void set_font(DREstring&, const int = 0) { };
  virtual void set_font_height(const int = 0) { };
  
  void surround(void);
  virtual void batch_on(void)
    { }
  virtual void batch_off(void)
    {update(); }
  virtual surface& dump(const char* filename)
    { return *this; }
  virtual void print(const char* printer_name)
    { }
  virtual void detach(void)
    { }
  virtual void detach(const char*)
    { }
  virtual void detach(ostream&)
    { }

  virtual int small_dot_size(void) { return 1; }
  virtual boolean hardcopy(void) = 0;
  virtual void update(void) { };

  void printer_is_none(void)
    { _dump_to_printer = &surface::_dump_to_none; }

};


#endif



