/* Copyright Steve Rabin, 2007. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright Steve Rabin, 2007"
 */

#include "DXUT.h"
#include "database.h"
#include "movement.h"
#include "gameobject.h"
#include "body.h"
#include "configure.h"
#include "tiny.h"
#include "WorldCollData.h"
#include "collision.h"

// BUGBUG: KLUDGE: m_speedWalk and m_speedJog have been chosen to make 
// Tiny's feet look planted (and not slide along the ground) as she is 
// walking or jogging. 

Movement::Movement( GameObject& owner )
: m_owner( &owner ),
  m_speedWalk( 4.f * 1.f / 5.7f ),
  m_speedJog( 4.f * 1.f / 2.3f )
{
	m_target.x = m_target.y = m_target.z = 0.0f;
}

Movement::~Movement( void )
{

}

void Movement::Animate( double dTimeDelta )
{
	if( m_owner->GetBody().GetSpeed() == 0.0f )
	{
		if (m_owner->IsTiny())
		{
			m_owner->GetTiny().SmoothLoiter();
		}
	}
	else
	{
		float speed = m_owner->GetBody().GetSpeed();
		D3DXVECTOR3 pos = m_owner->GetBody().GetPos();
		D3DXVECTOR3 toTarget = m_target - pos;

		if( D3DXVec3Length( &toTarget ) < 0.01f )
		{	//Notify target reached
			//m_owner->GetBody().SetPos( m_target );
			g_database.SendMsgFromSystem( m_owner, MSG_Arrived );
		}
		else
		{	
			//Point character towards target this frame
			D3DXVECTOR3 dir;
			D3DXVec3Normalize( &dir, &toTarget );
            dir *= speed < 0.0f ? -1.0f: 1.0f;	// needed for backward movement 
			m_owner->GetBody().SetDir( dir );

			//Move character towards target this frame
			double speedScale = 1.0f;
			if (m_owner->IsTiny())
			{
				speedScale = m_owner->GetTiny().GetSpeedScale();
			}
			D3DXVec3Scale( &dir, &dir, float( m_owner->GetBody().GetSpeed() * speedScale * dTimeDelta ) );

            CollSphere* pcs = m_owner->GetBody().GetPCollSphere();
            if (pcs)
            {
                // Do a tentative move to the new position and store it in pcs->center. 
			    D3DXVec3Add( &pcs->center, &dir, &pcs->center );

                // Do a collision test of sphere vs the world. 
                if (g_pWorldCollData->CollideSphereVsWorld(*pcs))
                {
                    // This is the collision response. That's it. 
                    pcs->center += gCollOutput.push;

                    // Notify that we've collided with the environment. 
                    g_database.SendMsgFromSystem( m_owner, MSG_CollideEnv );
                }
                pcs->center.y -= fCollYOffsetPlayer;  // undo offsetting of sphere off the ground 
			    m_owner->GetBody().SetPos( pcs->center );

                // Check CollSphere against other mobys. 
                if (pcs->VsMobys())
                {
                    // This is the collision response. 
                    pcs->center += gCollOutput.push;

        			g_database.SendMsgFromSystem( m_owner, MSG_CollideMoby );
                }
            }
		}
	}
	m_owner->GetInstance()->SetOrientation();
}

void Movement::SetIdleSpeed( void )
{
	m_owner->GetBody().SetSpeed( 0.0f );
	if (m_owner->IsTiny())
	{
		m_owner->GetTiny().SetIdleKey( true );
	}
}

void Movement::SetWalkSpeed( void )
{
	m_owner->GetBody().SetSpeed( m_speedWalk );
	if (m_owner->IsTiny())
	{
		m_owner->GetTiny().SetMoveKey();
	}
}

void Movement::SetJogSpeed( void )
{
	m_owner->GetBody().SetSpeed( m_speedJog );
	if (m_owner->IsTiny())
	{
		m_owner->GetTiny().SetMoveKey();
	}
}
