#include "lab_m1/tema1/tema1.h"
#include "lab_m1/tema1/transform2D.h"
#include "lab_m1/lab3/object2D.h"

using namespace std;
using namespace m1;

Tema1::Tema1() {
}

Tema1::~Tema1() {
}

float squareSide = 1;
float freq = 0.5f;

void Tema1::Init() {
    glm::ivec2 resolution = window->GetResolution();
    auto camera = GetSceneCamera();
    camera->SetOrthographic(0, (float)resolution.x, 0, (float)resolution.y, 0.01f, 400);
    camera->SetPosition(glm::vec3(0, 0, 50));
    camera->SetRotation(glm::vec3(0, 0, 0));
    camera->Update();
    GetCameraInput()->SetActive(false);

    glm::vec3 corner = glm::vec3(0, 0, 0);
    cx = corner.x + squareSide / 2;
    cy = corner.y + squareSide / 2;
    Mesh* square = object2D::CreateSquare("square", corner, squareSide, glm::vec3(0.2f, 0.7f, 0.3f), true);
    AddMeshToList(square);

    Mesh* baseTrapezoid1 = object2D::CreateTrapezoid("baseTrapezoid1", 110, 20, 100, glm::vec3(0.6f, 0.4f, 0.2f), true);
    AddMeshToList(baseTrapezoid1);
    Mesh* baseTrapezoid2 = object2D::CreateTrapezoid("baseTrapezoid2", 80, 17, 100, glm::vec3(0.2f, 0.2f, 0.6f), true);
    AddMeshToList(baseTrapezoid2);

    Mesh* circle = object2D::CreateCircle("circle", corner, 21, glm::vec3(0.6f, 0.4f, 0.2f), true);
    AddMeshToList(circle);

    Mesh* rectangle = object2D::CreateRectangle("rectangle", corner, 6.0f, 60.0f, glm::vec3(0.4f, 0.4f, 0.4f), true);
    AddMeshToList(rectangle);

    tank1X = 100;
    tank1Y = 100;
	turret1Angle = 0;

    tank2X = 1100;
    tank2Y = 100;
	turret2Angle = 0;

    glm::vec2 initialVelocity = glm::vec2(cos(turret1Angle), sin(turret1Angle)) * 100.0f;
    glm::vec2 projectilePosition = glm::vec2(tank1X, tank1Y) + glm::vec2(cos(turret1Angle), sin(turret1Angle)) * 6.0f;

}

void Tema1::RenderTank(float x, float y, float rotationAngle, float turretAngle) {
    // Transformarea pentru centrul bazei tancului
    glm::mat3 modelMatrix;

    // Mută centrul bazei tancului în punctul de pe teren
    modelMatrix = glm::mat3(1);
    modelMatrix *= transform2D::Translate(x, y);
    modelMatrix *= transform2D::Rotate(rotationAngle);

    // Trapezul de baza
    glm::mat3 baseMatrix = modelMatrix;
    baseMatrix *= transform2D::Translate(0, 26);
    RenderMesh2D(meshes["baseTrapezoid1"], shaders["VertexColor"], baseMatrix);

    baseMatrix = modelMatrix;
    baseMatrix *= transform2D::Translate(0, 9);
    baseMatrix *= transform2D::Scale(-1, -1);
    RenderMesh2D(meshes["baseTrapezoid2"], shaders["VertexColor"], baseMatrix);

    // Turretul circular superior
    glm::mat3 turretMatrix = modelMatrix;
    turretMatrix *= transform2D::Translate(0, 34.0f);
    RenderMesh2D(meshes["circle"], shaders["VertexColor"], turretMatrix);

    //  țeava tancului
    glm::mat3 barrelMatrix = modelMatrix;
    barrelMatrix *= transform2D::Translate(0, 37.0f);
    float barrelInclineAngle = glm::radians(-45.0f); // Poți ajusta acest unghi
    barrelMatrix *= transform2D::Rotate(barrelInclineAngle);
	barrelMatrix *= transform2D::Rotate(turretAngle);
    RenderMesh2D(meshes["rectangle"], shaders["VertexColor"], barrelMatrix);
}

float TerrainFunction(float t) {
    t *= freq;
    return sin(t) + 14.0f * sin(0.5f * t) + 14.0f * sin(0.6f * t) + 23.0f * sin(0.2f * t);
}

float CalculateSlopeAngle(glm::vec2 A, glm::vec2 B) {
    glm::vec2 V = B - A;
    return atan2(V.y, V.x);
}

// Function to find interpolated y-position for the tank's given x-position
float CalculateTankY(float tankX, glm::vec2 A, glm::vec2 B) {
    float t = (tankX - A.x) / (B.x - A.x);
    return A.y + t * (B.y - A.y);
}

void Tema1::Update(float deltaTimeSeconds) {
    glm::ivec2 resolution = window->GetResolution();

    int num_points = resolution.x / 5;
    std::vector<float> height_map(num_points);

    for (int i = 0; i < num_points; i++) {
        float x = i * (resolution.y / 10);
        float y = 10 * TerrainFunction(i) + 200;

        height_map[i] = y;

        if (i > 0) {
            float prev_x = (i - 1) * (resolution.y / 10);
            float prev_y = height_map[i - 1];

            modelMatrix = glm::mat3(1);
            float width = x - prev_x;
            float height = std::max(y, prev_y);

            modelMatrix *= transform2D::Translate(prev_x, prev_y);
            float sheerFactor = (y - prev_y) / (x - prev_x);
            modelMatrix *= transform2D::Sheer(sheerFactor);
            modelMatrix *= transform2D::Scale(width, height);
            modelMatrix *= transform2D::Translate(0, -squareSide);

            RenderMesh2D(meshes["square"], shaders["VertexColor"], modelMatrix);
            //if (tank1X >= prev_x && tank1X <= x) {
            //    glm::vec2 A(prev_x, prev_y);
            //    glm::vec2 B(x, y);

            //    // Calculate the interpolated y-position of the tank on the terrain
            //    tank1Y = CalculateTankY(tank1X, A, B);

            //    // Calculate the slope angle for rotation
            //    float rotationAngle = CalculateSlopeAngle(A, B);
            //    RenderTank(tank1X, tank1Y, rotationAngle, turret1Angle);
            //}

			if (tank2X >= prev_x && tank2X <= x) {
				glm::vec2 A(prev_x, prev_y);
				glm::vec2 B(x, y);

				// Calculate the interpolated y-position of the tank on the terrain
				tank2Y = CalculateTankY(tank2X, A, B);

				// Calculate the slope angle for rotation
				float rotationAngle = CalculateSlopeAngle(A, B);
				RenderTank(tank2X, tank2Y, rotationAngle, turret2Angle);
			}
        }
    }
    float rotationAngle = 0;
    for (int i = 1; i < num_points; i++) {
		float prev_x = (i - 1) * (resolution.y / 10);
		float prev_y = height_map[i - 1];
		float x = i * (resolution.y / 10);
		float y = height_map[i];

		if (tank1X > prev_x && tank1X < x) {
			glm::vec2 A(prev_x, prev_y);
			glm::vec2 B(x, y);

			// Calculate the interpolated y-position of the tank on the terrain
			tank1Y = CalculateTankY(tank1X, A, B);

			// Calculate the slope angle for rotation
			 rotationAngle = CalculateSlopeAngle(A, B);
             break;
		}
    }
//	printf("tank1X: %f, tank1Y: %f, rotationAngle: %f, turret1Angle: %f\n", tank1X, tank1Y, rotationAngle, turret1Angle);
	RenderTank(tank1X, tank1Y, rotationAngle, turret1Angle);
    
}


void Tema1::FrameStart()
{
    glClearColor(0.52f, 0.81f, 0.92f, 1);  // Light blue background
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::ivec2 resolution = window->GetResolution();
    glViewport(0, 0, resolution.x, resolution.y);
}

void Tema1::FrameEnd()
{
}


/*
 *  These are callback functions. To find more about callbacks and
 *  how they behave, see input_controller.h.
 */


void Tema1::OnInputUpdate(float deltaTime, int mods)
{
    if (window->KeyHold(GLFW_KEY_A)) {
        tank1X -= 200 * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_D)) {
        tank1X += 200 * deltaTime;
    }

	if (window->KeyHold(GLFW_KEY_LEFT)) {
		tank2X -= 200 * deltaTime;
	}

	if (window->KeyHold(GLFW_KEY_RIGHT)) {
		tank2X += 200 * deltaTime;
	}

    if (window->KeyHold(GLFW_KEY_W) && turret1Angle <= glm::pi<float>() / 1.5) {
        turret1Angle += 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_S) && turret1Angle > -0.5) {
        turret1Angle -= 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_UP) && turret2Angle < glm::pi<float>() / 1.5) {
        turret2Angle += 1.5f * deltaTime;
    }

    if (window->KeyHold(GLFW_KEY_DOWN) && turret2Angle > -0.5) {
        turret2Angle -= 1.5f * deltaTime;
    }
}


void Tema1::OnKeyPress(int key, int mods)
{
    // Add key press event
}


void Tema1::OnKeyRelease(int key, int mods)
{
    // Add key release event
}


void Tema1::OnMouseMove(int mouseX, int mouseY, int deltaX, int deltaY)
{
    // Add mouse move event
}


void Tema1::OnMouseBtnPress(int mouseX, int mouseY, int button, int mods)
{
    // Add mouse button press event
}


void Tema1::OnMouseBtnRelease(int mouseX, int mouseY, int button, int mods)
{
    // Add mouse button release event
}


void Tema1::OnMouseScroll(int mouseX, int mouseY, int offsetX, int offsetY)
{
}


void Tema1::OnWindowResize(int width, int height)
{
}#include "object2D.h"

#include <vector>

#include "core/engine.h"
#include "utils/gl_utils.h"


Mesh* object2D::CreateSquare(
    const std::string &name,
    glm::vec3 leftBottomCorner,
    float length,
    glm::vec3 color,
    bool fill)
{
    glm::vec3 corner = leftBottomCorner;

    std::vector<VertexFormat> vertices =
    {
        VertexFormat(corner, color),
        VertexFormat(corner + glm::vec3(length, 0, 0), color),
        VertexFormat(corner + glm::vec3(length, length, 0), color),
        VertexFormat(corner + glm::vec3(0, length, 0), color)
    };

    Mesh* square = new Mesh(name);
    std::vector<unsigned int> indices = { 0, 1, 2, 3 };

    if (!fill) {
        square->SetDrawMode(GL_LINE_LOOP);
    } else {
        // Draw 2 triangles. Add the remaining 2 indices
        indices.push_back(0);
        indices.push_back(2);
    }

    square->InitFromData(vertices, indices);
    return square;
}

Mesh* object2D::CreateTrapezoid(
	const std::string& name,
	float width,
	float height,
	float length,
	glm::vec3 color,
	bool fill)
{
	/*glm::vec3 corner = leftBottomCorner;*/

	std::vector<VertexFormat> vertices = {
		VertexFormat(glm::vec3(-width / 2, -height / 2, 0), color),
		VertexFormat(glm::vec3(width / 2, -height / 2, 0), color),
		VertexFormat(glm::vec3(width / 3, height / 2, 0), color),
		VertexFormat(glm::vec3(-width / 3, height / 2, 0), color)
	};


	Mesh* trapezoid = new Mesh(name);
	std::vector<unsigned int> indices = { 0, 1, 2, 3 };

	if (!fill) {
		trapezoid->SetDrawMode(GL_LINE_LOOP);
	}
	else {
		// Draw 2 triangles to fill the trapezoid
		indices.push_back(0);
		indices.push_back(2);
	}

	trapezoid->InitFromData(vertices, indices);
	return trapezoid;
}


Mesh* object2D::CreateCircle(
	const std::string& name,
	glm::vec3 center,
	float radius,
	glm::vec3 color,
	bool fill)
{
	std::vector<VertexFormat> vertices;
	std::vector<unsigned int> indices;

	int numTriangles = 100;
	float angle = 2 * M_PI / numTriangles;

	vertices.push_back(VertexFormat(center, color));
	for (int i = 0; i <= numTriangles; i++) {
		float x = center.x + radius * cos(i * angle);
		float y = center.y + radius * sin(i * angle);
		vertices.push_back(VertexFormat(glm::vec3(x, y, 0), color));
		indices.push_back(i);
	}

	Mesh* circle = new Mesh(name);
	if (!fill) {
		circle->SetDrawMode(GL_LINE_LOOP);
	}
	else {
		indices.push_back(1);
		indices.push_back(numTriangles);
		circle->SetDrawMode(GL_TRIANGLE_FAN);
	}

	circle->InitFromData(vertices, indices);
	return circle;
}

Mesh* object2D::CreateRectangle(
	const std::string& name,
	glm::vec3 leftBottomCorner,
	float length,
	float width,
	glm::vec3 color,
	bool fill)
{
	glm::vec3 corner = leftBottomCorner;

	std::vector<VertexFormat> vertices =
	{
		VertexFormat(corner, color),
		VertexFormat(corner + glm::vec3(length, 0, 0), color),
		VertexFormat(corner + glm::vec3(length, width, 0), color),
		VertexFormat(corner + glm::vec3(0, width, 0), color)
	};

	Mesh* rectangle = new Mesh(name);
	std::vector<unsigned int> indices = { 0, 1, 2, 3 };

	if (!fill) {
		rectangle->SetDrawMode(GL_LINE_LOOP);
	}
	else {
		// Draw 2 triangles. Add the remaining 2 indices
		indices.push_back(0);
		indices.push_back(2);
	}

	rectangle->InitFromData(vertices, indices);
	return rectangle;
}Vom folosi acest unghi în transformarea rotației tancului. Pentru a funcționa fără alte transformări ajutătoare de translație, tancul trebuie construit cu centrul laturei de jos în originea sistemului de coordonate. Altfel, coordonata acestui centru trebuie calculată, iar rotația se va face mai întâi translatând acel punct în origine, aplicând rotația și translâtând înapoi.


Utilizați atan2() pentru calcularea arctangentei.Tancul nu se misca corect de a lungul terenului, nu ia forma terenului pe pante