// G. Hagopian
// https://opentextbc.ca/physicstestbook2/chapter/elastic-collisions-in-one-dimension/
// https://opengameart.org/content/8-ball-pool-assets
#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>;

const int ballRadius = 28;
int numbCans = 2;
const sf::Vector2i dims(1200, 600);

int get_next() {
	static int n = 0;
	return n++;
}

void initialize(std::vector<sf::CircleShape>& Cans, 
	std::vector<sf::Vector2f>& vel,
	std::vector<sf::Texture>& canTextures) {
	std::string name;

	for (int i = 0; i < numbCans; ++i) {
		int number = get_next();
		std::ostringstream oss;
		oss << "assets\\can" << number << ".png";
		name = oss.str();
		std::cout << oss.str() << std::endl;
		if (!canTextures[i].loadFromFile(name))
			std::cerr << "couldn't load " << name;
		Cans[i].setRadius(ballRadius);
		Cans[i].setTexture(&canTextures[i]);
		Cans[i].setPosition((i + 1) * dims.x / (numbCans + 1), (i + 1) * dims.y / (numbCans + 1));
		Cans[i].setOrigin(ballRadius, ballRadius);
		vel[i].x = (double(rand() % 20)-10) / 3.;
		vel[i].y = (double(rand() % 10)-10) / 3.;
		//vel[i] = { (double(rand() % 20) - 10) / 7. , (double(rand() % 20) - 10) / 7. };
		name.clear();
	}
}

void update(std::vector<sf::CircleShape>& Cans, std::vector<sf::Vector2f>& vel) {
	for (int i = 0; i < numbCans; ++i) {
		Cans[i].move(vel[i]);
		//check for pocket
		if (abs(Cans[i].getPosition().x + ballRadius - 0.918*dims.x) < 22
			&& abs(Cans[i].getPosition().y - ballRadius-0.144*dims.y) < 22) {
			Cans.erase(Cans.begin() + i);
			numbCans--;
		}
		if (Cans[i].getPosition().x > dims.x - double(ballRadius) - 6.44e-2*dims.x 
		 || Cans[i].getPosition().x < ballRadius+ 6.44e-2*dims.x) {
			vel[i].x *= -1;
		}
		if (Cans[i].getPosition().y > dims.y - double(ballRadius) - 1.136e-1*dims.y 
		 || Cans[i].getPosition().y < ballRadius+ 1.136e-1*dims.y) {
			vel[i].y *= -1;
		}
	}
}

int main() {
	srand(unsigned(time(0)));
	
	sf::RenderWindow window(sf::VideoMode(dims.x, dims.y), "Billiards!");
	window.setFramerateLimit(240);
	

	/*https://www.sfml-dev.org/tutorials/2.5/graphics-sprite.php
	A texture is an image.  It's called a "texture" because it's role is to be mapped to a 2D entity.
  	
	A sprite is nothing more than a textured rectangle: Rectangular Entity + texture (image) = sprite
	https://en.wikipedia.org/wiki/Simple_and_Fast_Multimedia_Library
	https://github.com/SFML/SFML/wiki/Source:-AnimatedSprite
	https://github.com/SFML/SFML/wiki/Easy-Animations-With-Spritesheets

	Loading a texture
	Before creating any sprite, we need a valid texture. The class that encapsulates textures in SFML is, 
	unsurprisingly, sf::Texture. Since the only role of a texture is to be loaded and mapped to graphical 
	entities, almost all its functions are about loading and updating it.

	The most common way of loading a texture is from an image file on disk, which is done with the loadFromFile function.
	
	sf::Texture table;
	if (!table.loadFromFile("assets\\table.png")){
		std::cerr << "Failed to load image.\n";
	}

	You can also load an image file from memory (loadFromMemory), from a custom input stream (loadFromStream), or from an 
	image that has already been loaded (loadFromImage). The latter loads the texture from an sf::Image, which is a utility 
	class that helps store and manipulate image data (modify pixels, create transparency channel, etc.). 
	
	The pixels of an sf::Image stay in system memory, which ensures that operations on them will be as fast as possible, 
	in contrast to the pixels of a texture which reside in video memory and are therefore slow to retrieve or update but 
	very fast to draw.

	SFML supports most common image file formats. The full list is available in the API documentation.

	All these loading functions have an optional argument, which can be used if you want to load a smaller part of the image.
	load a 32x32 rectangle that starts at (10, 10)
	if (!texture.loadFromFile("assets\\table.png", sf::IntRect(10, 10, 32, 32)))
	{
		std::cerr << "Failed to load.";
	}
	The sf::IntRect class is a simple utility type that represents a rectangle. Its constructor takes the coordinates of the 
	top-left corner, and the size of the rectangle.  If you don't want to load a texture from an image, but instead want to 
	update it directly from an array of pixels, you can create it empty and update it later:
	create an empty 200x200 texture
	sf::Texture texture1;
	if (!texture1.create(200, 200))
	{
		// error...
	}
	Note that the contents of the texture are undefined at this point.

	To update the pixels of an existing texture, you have to use the update function. It has overloads for many kinds of 
	data sources:
	*/
	// update a texture from an array of pixels
	sf::Texture texture1;
	
	int width = 200, height = 200;
	sf::Uint8* pixels = new sf::Uint8[width * height * 4]; // * 4 because pixels have 4 components (RGBA)
	for (int i = 0; i < width * height * 4; ++i)
		pixels[i] = (i*i)%256;
	texture1.update(pixels);

	sf::Image rect09;
	rect09.create(200,200,pixels);
	texture1.loadFromImage(rect09);

	sf::RectangleShape rect10(sf::Vector2f(200, 200));
	rect10.setTexture(&texture1);
	rect10.setPosition(dims.x / 2, dims.y / 2);
	// update a texture from a sf::Image
	//sf::Image image;
	//...
	//texture1.update(image);

	// update the texture from the current contents of the window
	//sf::RenderWindow window;
	//...
	// this causes an exception 
	// texture1.update(window);
	//window.draw(image);
	/*These examples all assume that the source is of the same size as the texture. If this is not the case, i.e. if you want to update only a part of the texture, you can specify the coordinates of the sub-rectangle that you want to update. You can refer to the documentation for further details.

	Additionally, a texture has two properties that change how it is rendered.

The first property allows one to smooth the texture. Smoothing a texture makes pixel boundaries less visible (but the image a little more blurry), which can be desirable if it is up-scaled.
	*/
	sf::Texture table;
	if (!table.loadFromFile("assets\\table.png")) {
		std::cerr << "Failed to load image.\n";
	}
	sf::RectangleShape billiardsTable(sf::Vector2f(dims.x,dims.y));
	billiardsTable.setTexture(&table);

	

	std::vector<sf::Vector2f> vel(numbCans);
	std::vector<sf::CircleShape> Cans(numbCans);
	std::vector<sf::Texture> canTextures(numbCans);

	initialize(Cans, vel, canTextures);

	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(rect10);
		for (int i = 0; i < numbCans; ++i) {
			window.draw(Cans[i]);
		}
		update(Cans, vel);

		window.display();
	}

	return 0;
}