/*
	Copyright 2014 Michele "King_DuckZ" Santullo

	This file is part of CloonelJump.

	CloonelJump is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	CloonelJump is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with CloonelJump.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "moverleftright.hpp"
#include <algorithm>
#include <cmath>

namespace cloonel {
	namespace {
		float Clamp ( float parValue, float parMin, float parMax ) __attribute__((pure));
		float Clamp ( float parValue, float parMin, float parMax ) {
			assert(parMin <= parMax);
			return std::max(parMin, std::min(parMax, parValue));
		}
	} //unnamed namespace

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	MoverLeftRight::MoverLeftRight (float parMaxVelocity, float parMass, float parForce) :
		//TODO: mass does not belong to here
		m_velocity(0.0f),
		m_maxVelocity(parMaxVelocity),
		m_invMass(1.0f / parMass),
		m_force(parForce),
		m_movementTarget(0.0f)
	{
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	void MoverLeftRight::ApplyMotion (float parDelta) {
		//TODO: implement a movement that is more mathematically correct and
		//that feels nice.

		//const float forceDirection = std::abs(m_movementTarget) * 2.0f - 1.0f;
		const float notMoving = 1.0f - std::abs(m_movementTarget);
		const float friction = 1.757f * m_velocity * notMoving * parDelta;
		m_velocity += m_movementTarget * m_force * m_invMass * parDelta - std::copysign(friction, m_velocity);
		m_velocity = Clamp(m_velocity, -m_maxVelocity, m_maxVelocity);
		if (m_movementTarget == 0.0f and std::abs(m_velocity) < 0.1f)
			m_velocity = 0.0f;
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	float2 MoverLeftRight::GetOffset() const {
		return float2(m_velocity, 0.0f);
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	void MoverLeftRight::SetMovement (MovementDirectionType parDirection) {
		switch (parDirection) {
		case MovementDirection_Left:
			m_movementTarget = -1.0f;
			break;
		case MovementDirection_Right:
			m_movementTarget = 1.0f;
			break;
		case MovementDirection_Still:
			m_movementTarget = 0.0f;
			break;
		}
	}
} //namespace cloonel
