#include <iostream>
#include <cmath> //sqrt
#include <vector> //std::vector

//You can use double instead of float if you want it to be more accurate
//but for these I don't think they really need to be more than a few
//digits
struct Point //this will be a basic point without operators
{
    float x , y;
};

struct BoundingBox
{
    float top , left , width , height;
};

class Shape
{
    public:
    	virtual ~Shape(){}
        virtual float area( void ) const = 0;
        virtual float perimeter( void ) const = 0; //circumference for circles but oh well
    protected:
    	Point _origin;
	 	BoundingBox bounds;
};

//if you have a square derive from rectangle
//you might want to use virtual publics or consider
//composition instead of inheritance hierarchy 

class Square : public Shape
{
    public:
        Square( const float width , const Point origin );
        float area( void ) const;
        float perimeter( void ) const;
    private:
        float width;
};

Square::Square( const float width , const Point origin ) : width( width )
{
	_origin = origin;
	bounds.left = origin.x - width / 2.0f;
	bounds.top = origin.y - width / 2.0f;
	bounds.width = width;
	bounds.height = width;
}

float Square::area( void ) const
{
	return width * width;
}

float Square::perimeter( void ) const
{
	const int sides = 4;
	return sides * width; 
}


class Circle : public Shape
{
    public:
        Circle( const float radius , const Point origin );
        float area( void ) const;
        float perimeter( void ) const; //yeah its circum but in my example its perim
    private:
        float radius;
};

Circle::Circle( const float radius , const Point origin ) : radius( radius )
{
	_origin = origin;
	bounds.left = origin.x - radius;
	bounds.top = origin.y + radius;
	bounds.width = radius * 2; //radius * 2 = diameter
	bounds.height = bounds.width; //height and width are same in a circle
}

float Circle::area( void ) const
{
	const float pi = 3.14159f;
	return pi * radius * radius;
}

float Circle::perimeter( void ) const
{
	const float pi = 3.14159;
	return 2 * pi * radius;
}

//mine is a Equilateral Triangle
class Triangle : public Shape
{
	public:
		Triangle( const float length , const Point origin );
		float area( void ) const;
		float perimeter( void ) const;
	private:
		float length;	
};

Triangle::Triangle( const float length , const Point origin ) : length( length )
{
	_origin = origin;
	bounds.left = origin.x - length / 2.0f;
	bounds.top = origin.y - length / 2.0f;
	bounds.width = length;
	bounds.height = sqrt( length * length - length / 2.0f * length / 2.0f );
}

float Triangle::area( void ) const
{
	return length * bounds.height / 2.0f;
}

float Triangle::perimeter( void ) const
{
	const int sides = 3;
	return sides * length;
}

int main()
{
	Point origin{ 10 , 5 }; //center of shape is at 10 , 5
	
	std::vector<Shape *> shapes; //smart pointer would be better
	
	shapes.push_back( new Triangle(10,origin) );
	shapes.push_back( new Circle(5,origin) );
	shapes.push_back( new Square(10,origin) );
	
	for( const auto &it : shapes )
	{
		//triangle , circle , square
		std::cout << "Area: " << it->area() << " Perimeter: " << it->perimeter() << std::endl;
		delete it;
	}
		
	return 0;
}
