#include <iostream.h>
#include <assert.h>



/********************************************
* Screen:  Just a display.  Functions listed below
*********************************************
*/
const WIDTH = 80;
const HEIGTH = 24;
class Screen {
    public:
	void Clear(char c = '.');
	void Line(int x1, int y1, int x2, int y2, char c = '*');
	void Point(int x, int y, char c = '*');
	void Draw();
    private:
        char data[WIDTH][HEIGTH];
	void swap(int &a, int &b);
};

// Swap a and b.
void Screen::swap(int &a, int &b) {
	int temp = a;
	a = b;
	b = temp;
}
	

//
// Make every data item be zero.
void Screen::Clear(char c) {
	for(int y = 0;  y< HEIGTH; y++) {
		for( int x= 0; x < WIDTH; x++) {
			data[x][y] = c;
		}
	}
}

//
// Set a point on the screen.  We use
// mulitple assert()s to check for multiple
// errors so that the error message is more infomative.
void Screen::Point(int x, int y, char c) {

	// cout << "Drawing point (" << x << "," << y << ")\n";

	// Check arguments
	assert(x < WIDTH);
	assert(x >= 0);
	assert(y < HEIGTH);
	assert(y >= 0);

	// Draw the point
	data[x][y] = c;
}

// Draw a line from (x1,y1) -> (x2, y2).
// No need for error checking because Point does that.
void Screen::Line(int x1, int y1, int x2, int y2, char c) {

	// cout << "Drawing line from (" << x1 << "," << y1 << ") to (" << x2 << "," << y2 << ")\n";

	// make sure y1 <= y2
	if (y1 > y2) {
		swap(y1, y2);
		swap(x1, x2);
	}
	// The rest of this code only works for y1 <= y2
	assert(y1 <= y2);
	
	// Check for horizontal line.  Handle it special to
	// avoid divide by zero errors.
	if (x1 == x2) {
		for(int y = y1; y <= y2; y++)
			Point(x1, y, c);
	}
	else {
		float slope = (((float)y2 - y1)/(x2 - x1));
		if (slope < 0.5) {
			if (x1 <= x2) {
				for(int x = x1; x <= x2; x++) {
					int y = (int)(slope*(x - x1) + y1); 
					Point(x,y, c);
				}
			} 
			else {
				for(int x = x2; x <= x1; x++) {
					int y = (int)(slope*(x - x1) + y1);
					Point(x,y, c);
				}
			}
		}
		else {
			for(int y = y1; y <= y2; y++) {
				int x = (int)((1/slope)*(y - y1) + x1);
				Point(x,y, c);
			}
		}
	}
}

void Screen::Draw() {
	for(int y = 0; y < HEIGTH; y++) {
		cout << endl;
		for(int x = 0; x < WIDTH; x++) 
			cout << data[x][y];
	}
	cout  << endl;
}

/***********************************************
* Shape:  The parent of all shapes
************************************************
*/
class Shape {
    public:
	virtual void Draw(Screen &s) = 0;
};

/***************************************************
* Class Rectangle: a four sided rectilinear parallelogram
****************************************************
*/
class Rectangle : public Shape {
    public:
	void Draw(Screen &s);
    private:
	int top, bottom, left, right;
};

void Rectangle::Draw(Screen &s) {
	s.Line(left, top, right, top, '-');
	s.Line(right, top, right, bottom, '!');
	s.Line(right, bottom, left, bottom, '-');
	s.Line(left, bottom, left, top, '!');
}

Rectangle::Rectangle() {
	cout << "Rectangle: Enter the top, bottom, left, and right in that order\n";
	cin >> top >> bottom >> left >> right;
}

/*******************************************************
* Class RightTriangle
* A triangle with a verticle side on the left and a sloping side on the
* right
********************************************************
*/
class RightTriangle: public Shape {
    public:
	void Draw(Screen &s);
	RightTriangle();
    private:
        int top, bottom, left, right;
};

RightTriangle::RightTriangle() {
	cout << "RightTriangle: Enter top, bottom, left, right in that order\n";
	cin >> top >> bottom >> left >>  right;
}

void RightTriangle::Draw(Screen &s) {
	s.Line(left, top, left, bottom, '|');
	s.Line(left, bottom, right, bottom, '-');
	s.Line(right, bottom, left, top, '\\');
}


/********************************************
* Main::The Big Cheese
* Shows a menu, and prints the results
********************************************
*/
void main() {
	int choice;
	Shape *shape;
	Screen S;
	S.Clear();

	while (1) {
		cout << " 0 = quit\n" <<
			" 1 = clear screen\n" <<
			" 2 = Rectangle\n" <<
			" 3 = RightTriangle\n";
		cin >> choice;
		if (choice == 0) {
			exit(0);
		} 
		else if (choice == 1) {
			S.Clear();
			continue;
		}
		else if (choice ==  2) {
			shape = new Rectangle;
			assert(shape);
		}
		else if (choice == 3) {
			shape = new RightTriangle;
			assert(shape);
		}
		shape->Draw(S);
		delete shape;
		S.Draw();
	}
}



