#include <cmath>
#include "Player.hpp"
#include "Log.hpp"
#include "Animation.hpp"
#include "Asset.hpp"
#include "Alermath.hpp"

Player::Player(Collider* collider):
m_collider(collider),
m_dead(false),
m_jumping(false),
m_ms(80.f) {
	setPosition(199 * 32.f, 6 * 32.f);
	setOrigin(0.f, 0.f);
	addAnimation("data/nem-run.png", 600, "run", true, 32);
	addAnimation("data/nem-jump.png", 3000, "jump", true, 32);
	addAnimation("data/nem-plop.png", 3000, "plop", false, 32);
	setAnimation("run");
	setAnimationSpeed(1.f);
	m_hop.setVolume(20.f);
	animate();
}

Player::~Player() {

}

void Player::revive() {
	m_dead = false;
	m_jumping = false;
	sf::Vector2i below;
	below.x = 19;
	below.y = 1;

	while(!(m_collider->isSolid(below.x, below.y) && !m_collider->isSolid(below.x, below.y - 1))) {
		move(0.f, 32.f);
		below.y++;
        if(below.y > 12) {
            setPosition(getPosition().x, 0.f);
            break;
        }
	}
	
	setAnimation("run");
	animate();
}

void Player::update(float delta) {
	animate();
	
	if(m_dead == true) {
		return;
	}

	sf::Vector2i belowL, belowR, ahead, in;
	static float jump = 0.f;
	static Vector2f jump_pos;
	static sf::Clock clock;
	belowL.x = (getPosition().x + 2.f - m_collider->getLocalX()) / 32.f;
	belowL.y = (getPosition().y + 16.f) / 32.f + 1;
	belowR.x = (getPosition().x + 30.f - m_collider->getLocalX()) / 32.f;
	belowR.y = (getPosition().y + 16.f) / 32.f + 1;
	ahead.x = (getPosition().x - 1.f - m_collider->getLocalX()) / 32.f;
	ahead.y = ((getPosition().y + 31.f) / 32.f);
	in.x = (getPosition().x + 16.f - m_collider->getLocalX()) / 32.f;
	in.y = (getPosition().y + 16.f) / 32.f;
	if(jump == 0.f && !m_jumping) {  
		if(!m_collider->isSolid(belowL.x, belowL.y) && !m_collider->isSolid(belowR.x, belowR.y)) {
			jump = 32.f;
		} else if(m_collider->isSolid(ahead.x, ahead.y)) {
			m_jumping = true;
			jump_pos = getPosition();
			clock.restart();
			std::string str = "data/hop";
			str.push_back(rand() % HOPS + '0');
			str += ".ogg";
			m_hop.setBuffer(Asset::sound(str));
			m_hop.play();
		} 
	}
	
	if(m_jumping) {
		float dt = clock.getElapsedTime().asSeconds() * 2.f;
		float dx, dy;
		if(dt < 0.5f) {
			dx = 32.f * std::pow(dt, 2);
			dy = 48.f - 192.f * std::pow(dt - 0.5f, 2);
		} else {
			dx = 32.f * std::pow(dt, 2);
			dy = 48.f - 64.f * std::pow(dt - 0.5f, 2);
		}
		setPosition(jump_pos - Vector2f(dx, dy));
		if(dt >= 1.f) {
			setPosition(jump_pos.x - 32.f, jump_pos.y - 32.f);
			m_jumping = false;
		}
	} else {
		if(jump != 0.f) {
			setAnimation("jump");
			jump -= math::sgn(jump) * delta * 200.f;
			move(0.f, math::sgn(jump) * delta * 200.f);
			if(std::fabs(jump) < 3.f) {
				move(0.f, jump);
				jump = 0.f;
			}
		} else {
			setAnimation("run");
			move(-delta * m_ms, 0.f);
		}
	}
	
	if(!m_collider->isSafe(ahead.x, ahead.y) || !m_collider->isSafe(in.x, in.y) || m_collider->isSolid(in.x, in.y)) {
		setAnimation("plop");
		m_dead = true;
		m_hop.setBuffer(Asset::sound("data/ouch.ogg"));
		m_hop.play();
	}
}

void Player::turboBoost() {
	setAnimationSpeed(2.f);
	m_ms *= 2.f;
}