// File: ass2.cpp - CIS29 - Assignment 2 Solution

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cmath>		// for sqrt()
using namespace std;


const double PI = 3.141592654;

class Solid
{
public:
	Solid() {}
	virtual double volume() const = 0;
	virtual double surfaceArea() const = 0;
	virtual const char* const name() const = 0;
};

class Rectangular : public Solid
{
public:
	Rectangular(double length = 0, double width = 0, double height = 0);
	double volume() const;
	double surfaceArea() const;
	virtual const char* const name() const = 0;
protected:
	double length_;
	double width_;
	double height_;
};


Rectangular::Rectangular(double length, double width, double height)
:length_(length), width_(width), height_(height)
{
}

double Rectangular::volume() const
{
	return length_ * width_ * height_;
}

double Rectangular::surfaceArea() const
{
	return 2*(length_ * width_ + length_ * height_ + width_ * height_);
}

class RectangularPrism : public Rectangular
{
public:
	RectangularPrism(double length = 0, double width = 0, double height = 0);
	const char* const name() const { return "rectangular prism"; }
};

RectangularPrism::RectangularPrism(double length, double width, double height)
: Rectangular(length, width, height)
{}

class Cube : public RectangularPrism
{
public:
	Cube(double s = 0)
		: RectangularPrism(s,s,s) {}
	const char* const name() const { return "cube"; }
};

class Circular : public Solid
{
public:
	Circular(double radius = 0);
	double radius() const;
	virtual double volume() const = 0;
	virtual double surfaceArea() const = 0;
	virtual const char* const name() const = 0;
protected:
	double radius_;
};

Circular::Circular(double radius)
: radius_(radius)
{}

double Circular::radius() const
{
	return radius_;
}

class Sphere : public Circular
{
public:
	Sphere(double radius = 0);
	double volume() const;
	double surfaceArea() const;
	const char* const name() const;
};

Sphere::Sphere(double radius)
: Circular(radius)
{}

double Sphere::volume() const
{
	return 4./3. * PI * radius_ * radius_ * radius_;
}

double Sphere::surfaceArea() const
{
	return 4. * PI * radius_ * radius_;
}

const char* const Sphere::name() const
{
	return "sphere";
}

class Cylinder : public Circular
{
protected:
	double height_;
public:
	Cylinder(double radius = 0, double height = 0);
	double volume() const;
	double surfaceArea() const;
	const char* const name() const;
};


Cylinder::Cylinder(double radius, double height)
: Circular(radius), height_(height)
{}

double Cylinder::volume() const
{
	return PI * radius_ * radius_ * height_;
}

double Cylinder::surfaceArea() const
{
	return 2. * PI * radius_ * (height_ + radius_);
}

const char* const Cylinder::name() const
{
	return "cylinder";
}


int main()
{
	double d1, d2, d3;
	char code[3];
	ifstream fin("/deanza/data/ass2data");
	if (!fin) {
		cerr << "Unable to open /deanza/data/ass2data\n";
		exit(-2);
	}
	Solid* ptrSolid;
	cout << fixed << setprecision(4);

	for (unsigned i = 0; i< 50; ++i) {
		fin >> code;
		if (!fin) {
			break;
		}
		if (!strcmp(code,"cy")) {
			fin >> d1 >> d2;
			ptrSolid = new Cylinder(d1,d2);
		}
		else if (!strcmp(code,"sp")) {
			fin >> d1;
			ptrSolid = new Sphere(d1);
		}
		else if (!strcmp(code,"re")) {
			fin >> d1 >> d2 >> d3;
			ptrSolid = new RectangularPrism(d1,d2,d3);
		}
		else if (!strcmp(code,"cu")) {
			fin >> d1;
			ptrSolid = new Cube(d1);
		}
		else {
			cout << "************* " << code[0]<< code[1] << endl;
			continue;
		}
		cout << left << setw(18) << ptrSolid->name() << right << setw(15);
		if (ptrSolid->surfaceArea()>10000.) {
			cout << scientific << setprecision(2) << ptrSolid->surfaceArea();
		}
		else {
			cout << fixed << setprecision(4) << ptrSolid->surfaceArea();
		}
		if (ptrSolid->volume()>10000.) {
			cout << setw(15) << scientific << setprecision(2) << ptrSolid->volume();
		}
		else {
			cout << setw(15) << fixed << setprecision(4) << ptrSolid->volume();
		}
		cout << endl;
		delete ptrSolid;
	}
	fin.close();

	system("pause");

	return 0;
}