#define _USE_MATH_DEFINES
#include <DataStructures.h>
#include <vector>
#include <array>
#include <math.h>
#include <cmath>
#include <string>
#include <iostream>
void CameraData::accCamera(float acc[3], float time) {
    for (int i = 0; i < 3; i++)
        acceleration[i] += acc[i] * acc_mul;
}

void CameraData::rotateCamera(float dx, float dy) {
    rotation[1] += dx * sensitivity * (500.0f/m_width);
    if (rotation[0] + dy * sensitivity * (500.0f / m_width) < -90)
        rotation[0] = -90;
    else if (rotation[0] + dy * sensitivity * (500.0f / m_width)  > 90)
        rotation[0] = 90;
    else
        rotation[0] += dy * sensitivity * (500.0f / m_width);


    rotation[1] = (float)fmod(rotation[1], 360);

    if((abs(dx) > 0.0001f) || (abs(dy) > 0.0001f))
        m_changed = true;
}

void CameraData::CopyData(shader_data_t& shader_data) {
    shader_data.camera_position = { position[0], position[1], position[2], 0 };
    shader_data.camera_rotation = { rotation[0], rotation[1], rotation[2], 0 };
}

bool CameraData::HasChanged() {
    return m_changed;
}

void CameraData::SetChanged(bool ch) {
    m_changed = ch;
}

float DegToRad(float deg) {
    return (float)(deg * (M_PI / 180.0f));
}

void CameraData::updateCameraData(float time, GLFWwindow* window) {
    std::vector<std::vector<float>> move_vectors;
    std::vector<float> forward = { cos(DegToRad(rotation[1])), 0.0f, sin(DegToRad(rotation[1])) };
    std::vector<float> up = { 0, 1.0f, 0 };
    std::vector<float> right = { cos(DegToRad(rotation[1] + 90)), 0.0f, sin(DegToRad(rotation[1] + 90)) };
    move_vectors.push_back(forward);
    move_vectors.push_back(up);
    move_vectors.push_back(right);
    //update position
    for (int i = 0; i < 3; i++) {
        temp[0] = position[i];
        temp[1] = rotation[i];

        //acceleration[0] = 1.0f * acc_mul;

        float accell = 0;
        //if (true) {

        for (int x = 0; x < 3; x++)
            accell += acceleration[x] * move_vectors[x][i];
        accell *= time;

        velocity[i] += accell;

        if (velocity[i] > max_v[i])
            velocity[i] = max_v[i];
        else if (velocity[i] < -max_v[i])
            velocity[i] = -max_v[i];

        position[i] += velocity[i] * time;
        //}
        //else {
        float sum = abs(velocity[0]) + abs(velocity[1]) + abs(velocity[2]);
        float part_friction = abs((velocity[i] / sum)) * friction;
        if (sum != 0) {
            if (velocity[i] > 0) {
                if (part_friction * time > velocity[i])
                    velocity[i] = 0;
                else
                    velocity[i] -= part_friction * time;
            }
            else if (velocity[i] < 0) {
                if (part_friction * time < velocity[i])
                    velocity[i] = 0;
                else
                    velocity[i] += part_friction * time;
            }
            position[i] += velocity[i] * time;
        }
        //}

        if ((temp[0] != position[i]) || (temp[1] != rotation[i]))
            m_changed = true;
    }
    for (int i = 0; i < 3; i++)
        acceleration[i] = 0;

}
void CameraData::updateCameraData(float time) {
    std::vector<std::vector<float>> move_vectors;
    std::vector<float> forward = { cos(DegToRad(rotation[1])), 0, sin(DegToRad(rotation[1])) };
    std::vector<float> up = { 0, 1.0f, 0 };
    std::vector<float> right = { cos(DegToRad(rotation[1] + 90)), sin(DegToRad(rotation[0])), sin(DegToRad(rotation[1] + 90)) };

    move_vectors.push_back(forward);
    move_vectors.push_back(up);
    move_vectors.push_back(right);

    //update position
    for (int i = 0; i < 3; i++) {
        temp[0] = position[i];
        temp[1] = rotation[i];

        float accell = 0;

        for (int x = 0; x < 3; x++)
            accell += acceleration[x] * move_vectors[x][i];
        accell *= time;

        velocity[i] += accell;

        if (velocity[i] > max_v[i])
            velocity[i] = max_v[i];
        else if (velocity[i] < -max_v[i])
            velocity[i] = -max_v[i];

        position[i] += velocity[i] * time;

        float sum = abs(velocity[0]) + abs(velocity[1]) + abs(velocity[2]);
        float part_friction = abs((velocity[i] / sum)) * friction;
        if (sum != 0) {
            if (velocity[i] > 0) {
                if (part_friction * time > velocity[i])
                    velocity[i] = 0;
                else
                    velocity[i] -= part_friction * time;
            }
            else if (velocity[i] < 0) {
                if (part_friction * time < velocity[i])
                    velocity[i] = 0;
                else
                    velocity[i] += part_friction * time;
            }
            position[i] += velocity[i] * time;
        }

        if ((temp[0] != position[i]) || (temp[1] != rotation[i]))
            m_changed = true;
    }
    for (int i = 0; i < 3; i++)
        acceleration[i] = 0;

}

void shader_data_t::UpdateSeed() {
    _Seed = getRand();
}
void shader_data_t::UpdateWindowSize(int width, int height) {
    screenSize[0] = width;
    screenSize[1] = height;
}
void shader_data_t::GetWindowSize(int& width, int& height) {
    width = screenSize[0];
    height = screenSize[1];
}
int shader_data_t::GetWidth() {
    return screenSize[0];
}
int shader_data_t::GetHeight() {
    return screenSize[1];
}
void CameraData::UpdateWindowSize(int width, int height) {
    m_width = width;
    m_height = height;
}