// Shape.h
//
// A "bare bones" Shape program.
// All methods are inline'd for convenience.
// Notice that the commented out code is not needed,
// since it simply implements the default behavior of C++.
//
// by Dr. Jeff Blessing,
// May 11, 1998.

//#ifndef BBSHAPE_H
//#define BBSHAPE_H

#include <iostream>
#include <cassert>
using namespace std;

// An Abstract Base Class for 2D Shapes:

class Shape
{
public:
	Shape();
	static int counter;
	virtual void draw() const = 0;	// abstract method declaration
protected:
	int	id;
};

int Shape::counter = 0;		// initialize counter outside the class!

inline Shape::Shape()
{
	id = ++counter;
}

// A Point class for 2D graphics:

class Point
{
public:
	Point(double xval = 0, double yval = 0): x(xval), y(yval) { }
	void draw() const;
private:
	double	x;
	double	y;
};

inline void Point::draw() const
{
	cout << "(" << x << ", " << y << ")";
}

// Lines are described by 2 points and a width:

class Line: public Shape
{
public:
	Line(const Point& p1 = Point(0,0),
		 const Point& p2 = Point(0,0),
		 double wid = 0.0)
		 : pt1(p1), pt2(p2), width(wid) { }
	virtual void draw() const;
protected:
	Point	pt1;
	Point	pt2;
	double	width;
};

inline void Line::draw() const
{ 
	cout << "Draw Line-" << id << " from ";
	pt1.draw();
	cout << " to ";
	pt2.draw();
	cout << endl;
}

// Fancy Lines are lines with an added style feature:

class FancyLine: public Line
{
public:
	enum LineType { SOLID, DASHED, DOTTED };
	FancyLine(const Point& p1 = Point(0,0),
			  const Point& p2 = Point(0,0),
			  LineType lt = SOLID,
			  double wid = 0.0)
			  : Line(p1, p2, wid), line_type(lt) { }
	virtual void draw() const;
private:
	LineType line_type;
};

inline void FancyLine::draw() const
{
	cout << "Draw Fancy-Line-" << id << " from ";
	pt1.draw();
	cout << " to ";
	pt2.draw();
	cout << " of type ";
	cout << line_type;
	cout << endl;
}

// Circles are represented by a center point and a radius:

class Circle: public Shape
{
public:
	Circle(const Point& c = Point(0,0),
		   double r = 0.0)
		   : center(c), radius(r) { }
	virtual void draw() const;
private:
	Point	center;
	double	radius;
};

inline void Circle::draw() const
{
	cout << "Draw Circle-" << id << " centered at ";
	center.draw();
	cout << " with radius " << radius << endl;
}

// Note:  The container/iterator idiom implementation below is
// placed here for completeness purposes for my CS-481 students.
// Notice again that the commented out code is not needed,
// since it simply implements the default behavior of C++.
// Also, please pardon my "lazy" inlining of methods below.

// ShapeList - a container class for Shapes:

class ShapeList
{
public:
	ShapeList(): count(0) { }
	~ShapeList()
	{
		for (int ii=0; ii < count; ii++)
			delete array[ii];
	}
	void add(Shape* sp)
	{
		assert(count < size);
		cout << "Add list element " << count << endl;
		array[count++] = sp;
	}
//	bool operator==(ShapeList& sl)
//	{
//		if (count != sl.count) return false;
//		for (int i=0; i < count; i++)
//			if (array[i] != sl.array[i])
//				return false;
//		return true;
//	}
//	bool operator!=(ShapeList& sl)
//	{ return !(*this == sl); }		// use == above!
private:
	enum {size = 10};
	Shape*	array[size];
	int		count;
	friend class ShapeListIter;
};

// ShapeListIter - an iterator class for Shape lists:

class ShapeListIter
{
public:
	ShapeListIter(ShapeList& sl) : list(sl), index(0) {}
//	ShapeListIter(const ShapeListIter& sli)
//		: list(sli.list), index(sli.index) {}
//	void Reset() { index = 0; }
	ShapeListIter& operator++() { index++; return *this; }
	ShapeListIter operator++(int)
		{ ShapeListIter sli(*this); index++; return sli; }
	Shape* operator*()
		{ return (index < list.count) ? list.array[index] : NULL; }
//	ShapeListIter& operator=(const ShapeListIter& rhs)
//	{
//		list  = rhs.list;
//		index = rhs.index;
//		return *this;
//	}
//	bool operator==(ShapeListIter& sli)
//	{
//		if ((list == sli.list) && (index == sli.index))
//			return true;
//		else
//			return false;
//	}
//	bool operator!=(ShapeListIter& sli)
//	{
//		if ((list != sli.list) || (index != sli.index))
//			return true;
//		else
//			return false;
//	}
private:
	ShapeList&	list;
	int			index;
};

//#endif BBSHAPE_H