//			Drawable shapes
//
// Handling a collection of polymorphic objects in a conventional OOP style:
// an abstract base class (interface) overridden/implemented in
// concrete classes.
//
// $Id: Shapes-oop.cc,v 1.2 2003/01/27 21:29:49 oleg Exp oleg $

#include <iostream>
using std::cerr;
using std::endl;

// An Abstract Base Class (interface)

class Shape {
public:
  virtual void draw(void) = 0;
  virtual void offset_by(const float x, const float y) = 0;
  virtual void set_dim(const float width, const float height) = 0;
};

// This is supposed to be a list of shapes to draw
// For simplicity, we'll hold three shapes only

class Shapes {
  Shape *s1, *s2, *s3;
public:
  Shapes(Shape * const _s1, Shape * const _s2, Shape * const _s3)
    : s1(_s1), s2(_s2), s3(_s3) {}
  void draw(void) { s1->draw(); s2->draw(); s3->draw(); }
  void pack(void)
  { s1->offset_by(0,1); s2->offset_by(2,3); s3->offset_by(4,5); }
  void resize(void)
  { s1->set_dim(10,10); s2->set_dim(10,11); s3->set_dim(11,12); }
};


// Two implementations of the Abstract datatype Shape

class Rectangle: public Shape {
  float x, y;
  float width, height;
public:
  Rectangle(const float _width, const float _height) :
    x(0), y(0), width(_width), height(_height) {}
  virtual void draw(void)
  { cerr << "Drawing a rectangle [" << x << ", " << y
	 << "] - [" << (x+width) << ", " << (y+height) 
	 << "]" << endl; }
  virtual void offset_by(const float x, const float y)
  { this->x += x; this->y += y; }
  virtual void set_dim(const float width, const float height)
  { this->width = width; this->height = height; }
};

class Ellipse: public Shape {
  float x, y;
  float width, height;
public:
  Ellipse(const float _width, const float _height) :
    x(0), y(0), width(_width), height(_height) {}
  virtual void draw(void)
  { cerr << "Drawing an ellipse [" << x << ", " << y
	 << "] axes " << width << " and " << height << endl; }
  virtual void offset_by(const float x, const float y)
  { this->x += x; this->y += y; }
  virtual void set_dim(const float width, const float height)
  { this->width = width; this->height = height; }
};


// The test

int main(void)
{
  cerr << "Instantiating shapes..." << endl;
  Shapes shapes(new Rectangle(1,2), new Ellipse(5,5),
		new Rectangle(7,7));
  cerr << "Drawing ..." << endl;
  shapes.draw();
  cerr << "Packing ..." << endl;
  shapes.pack();
  shapes.draw();
  cerr << "Resizing .. " << endl;
  shapes.resize();
  shapes.draw();
  // Assume the garbage will be collected
  cerr << "\nAll done" << endl;
  return 0;
}
