// G. Hagopian -- PPP14-ex01
#include <iostream>
#include<vector>
#include <SFML/Graphics/Image.hpp>
//#include <SFML/Graphics/ImageLoader.hpp>
#include <SFML/Graphics.hpp>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>;
#include <cmath>

sf::Vector2i dims(1200, 800);
double pi = 3.141592635;
/*
1. Define two classes Smiley and Frowny, which are both derived 
from classes Drawable and Transformable and have two 
eyes and a mouth. Next, derive classes from Smiley and 
Frowny which add an appropriate hat to each.
*/

class Smiley : public sf::Drawable, public sf::Transformable {  //, public sf::Transformable
public:
	int smileSegments = 10;
	sf::CircleShape outline;
	sf::CircleShape leftEye, rightEye;
	sf::VertexArray smile;
	sf::Vector2f pos;
	//Smiley() {}
	Smiley(sf::RenderTarget& target, double r = 100, double a = pi/3, sf::Vector2f p = { 0,0 }) 
		: radius(r), angle(a), pos(p) {
		smile.setPrimitiveType(sf::LineStrip);
		smile.resize(smileSegments);  //states.transform *= getTransform();
		outline.setFillColor(sf::Color::Blue);
		outline.setRadius(radius);
		outline.setOrigin(sf::Vector2f(r, r));
		leftEye.setRadius(r/10);
		leftEye.setFillColor(sf::Color::Yellow);
		rightEye.setRadius(r/10);
		rightEye.setFillColor(sf::Color::Red);
		leftEye.setOrigin(outline.getOrigin() + sf::Vector2f(-r / 2, -r / 2));
		rightEye.setOrigin(outline.getOrigin() + sf::Vector2f(-1.26*r , -r / 2));
		for (int i = 0; i < smileSegments; ++i)
			smile[i] = sf::Vector2f( r / 2 * cos((pi-a)/2+a * i / (double(smileSegments-1))), 
				                     r / 2 * sin((pi-a)/2+a * i / (smileSegments-1)));
		//update();
	}

	void setPosition(const sf::Vector2f& position) {
		sf::Vector2f delta = position - pos;
		outline.move(delta);
		leftEye.move(delta);
		rightEye.move(delta);
		for (int i = 0; i < smileSegments; ++i) {
			smile[i].position += delta;
		}
		//smile.setPosition(position);
	}


	void move(const sf::Vector2f& delta) {
		outline.move(delta);
		leftEye.move(delta);
		rightEye.move(delta);
		//for (int i = 0; i < smileSegments; ++i) {
		//	smile[i].position += delta;
		//}
		//smile.setPosition(position);
	}

	void setRadius(const double r) {
		radius = r;
		//update();
	}
	double getRadius() { return radius; }
protected:
	double radius;
	double angle;
private:
	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
		target.draw(outline);
		target.draw(rightEye);
		target.draw(leftEye);
		target.draw(smile);
	}
	//double eyesize;
};

class Frowney : public sf::Drawable, public sf::Transformable {  //, public sf::Transformable
public:
	int frownSegments = 10;
	sf::CircleShape outline;
	sf::CircleShape leftEye, rightEye;
	sf::VertexArray frown;
	sf::Vector2f pos;
	Frowney(sf::RenderTarget& target, double r = 100, double a = pi / 3, sf::Vector2f p = { 0,0 })
		: radius(r), angle(a), pos(p) {
		frown.setPrimitiveType(sf::LineStrip);
		frown.resize(frownSegments);
		outline.setFillColor(sf::Color::Blue);
		outline.setRadius(radius);
		outline.setOrigin(sf::Vector2f(r, r));
		leftEye.setRadius(r / 10);
		leftEye.setFillColor(sf::Color::Yellow);
		rightEye.setRadius(r / 10);
		rightEye.setFillColor(sf::Color::Red);
		leftEye.setOrigin(outline.getOrigin() + sf::Vector2f(-r / 2, -r / 2));
		rightEye.setOrigin(outline.getOrigin() + sf::Vector2f(-1.26 * r, -r / 2));
		for (int i = 0; i < frownSegments; ++i)
			frown[i] = sf::Vector2f(r / 2 * cos((pi - a) / 2 + a * i / (frownSegments - 1)),
				                    r/2-r / 2 * sin((pi - a) / 2 + a * i / (frownSegments - 1)));
		//update();
	}

	void setPosition(const sf::Vector2f& position) {
		sf::Vector2f delta = position - pos;
		outline.move(delta);
		leftEye.move(delta);
		rightEye.move(delta);
		for (int i = 0; i < frownSegments; ++i) {
			frown[i].position += delta;
		}
		//smile.setPosition(position);
	}


	void move(const sf::Vector2f& delta) {
		outline.move(delta);
		leftEye.move(delta);
		rightEye.move(delta);
		//for (int i = 0; i < smileSegments; ++i) {
		//	smile[i].position += delta;
		//}
		//smile.setPosition(position);
	}

	void setRadius(const double r) {
		radius = r;
		//update();
	}
	double getRadius() { return radius; }

private:
	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
		target.draw(outline);
		target.draw(rightEye);
		target.draw(leftEye);
		target.draw(frown);
	}
	double radius;
	double angle;
	//double eyesize;
};

/*class Smileyhat : public Smiley {
	sf::ConvexShape hat;
	Smileyhat()  {  //sf::RenderTarget& target, double r, double a) {
		hat.setPointCount(5);
		hat.setPoint(0, sf::Vector2f(radius, radius/5));
		hat.setPoint(1, sf::Vector2f(2.2*radius, 0));
		hat.setPoint(2, sf::Vector2f(radius, -1.1 * radius));
		hat.setPoint(3, sf::Vector2f(-0.2*radius, 0));
		hat.setPoint(4, sf::Vector2f(radius, radius / 5));
		hat.setOutlineColor(sf::Color::Green);
		hat.setOutlineThickness(5);
		hat.setPosition(0, 0);
	}
private:
	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
		target.draw(hat);
	}
};*/

int main() {
	srand(unsigned(time(0)));
	sf::RenderWindow window(sf::VideoMode(dims.x, dims.y), "Smiley Faces!");
	window.setFramerateLimit(60);

	
	sf::CircleShape shape(50);
	shape.setFillColor(sf::Color(150, 50, 250,0));

	// set a 10-pixel wide orange outline
	shape.setOutlineThickness(10);
	shape.setOutlineColor(sf::Color(250, 150, 100));
	/*
	 By default, the outline is extruded outwards from the shape (e.g. if you have a 
	 circle with a radius of 10 and an outline thickness of 5, the total radius of 
	 the circle will be 15). You can make it extrude towards the center of the shape 
	 instead, by setting a negative thickness.

	To disable the outline, set its thickness to 0. If you only want the outline, you 
	can set the fill color to sf::Color::Transparent. 
	
	Texture

	Shapes can also be textured, just like sprites. To specify a part of the texture 
	to be mapped to the shape, you must use the setTextureRect function. It takes the 
	texture rectangle to map to the bounding rectangle of the shape. This method doesn't 
	offer maximum flexibility, but it is much easier to use than individually setting 
	the texture coordinates of each point of the shape.
	*/
	sf::CircleShape shape2(50);

	sf::Texture texture;
	texture.loadFromFile("assets//table.png");
	// map a 100x100 textured rectangle to the shape
	shape2.setTexture(&texture); // texture is a sf::Texture
	shape2.setTextureRect(sf::IntRect(10, 10, 100, 100));
	shape2.setPosition(100, 100);
	
	Smiley happyface(window, 100, pi/2);
	Smiley happyface2{ happyface };
	Frowney sadface(window, 100, 2 * pi / 3);
	//Smileyhat hattedSmile();
	happyface.setPosition(sf::Vector2f(400, 400));
	happyface2.setPosition(sf::Vector2f(800, 400));
	sadface.setPosition(sf::Vector2f(600, 450));
	
	double t = 0.0;
	double dt = 1.0 / 60.;
	sf::ConvexShape polygon;
	polygon.setPointCount(3);
	polygon.setPoint(0, sf::Vector2f(0, 0));
	polygon.setPoint(1, sf::Vector2f(0, 10));
	polygon.setPoint(2, sf::Vector2f(25, 5));
	polygon.setOutlineColor(sf::Color::Red);
	polygon.setOutlineThickness(1);
	polygon.setPosition(100, 200);
	polygon.setScale(5, 6);
	polygon.setPointCount(4);
	polygon.setPoint(3, sf::Vector2f(45, 15));
	//sf::Shape ss;  // can't do that--abstract class with pure virtual functions
	//Fractal heregoesnothing({ 100, dims.x - 100, dims.x / 2 }, { 100,100, dims.y - 100, }, 5);
	while (window.isOpen())
	{
		sf::Event event;

		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed)
				window.close();
		}
		window.clear();
		//draw

		//window.draw(billiardsTable);
		window.draw(shape);
		window.draw(shape2);
		
		t += dt;
		std::cout << "fmod(" << t << ", 40) = " << fmod(t, 40) << std::endl;
		window.draw(polygon);
		//happyface.move(sf::Vector2f{ 1, -1 });
		window.draw(happyface);
		window.draw(happyface2);
		window.draw(sadface);
		//window.draw(hattedSmile);
		window.display();
	}
}