//////////////////////////////////////////////////////////////////////////////
//
// Asura_ServerNode_GamesceneNode.cpp
//
// Created by NJD - 12 October 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

#ifdef ASURA_USE_AXON

// header
#include "Entity/Locations/OrientedNode/GamesceneNode/Asura_ServerNode_GamesceneNode.h"

// asura
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Entity/Asura_Entity_Classification.h"
#include "Entity/Asura_StaticMessage_System.h"
#include "Network/Asura_Message.h"
#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)
#include "Streaming/Asura_Streaming_System.h"
#endif //#if defined(ASURA_USE_STREAMING) && !defined(ASURA_TOOLS)

// axon
//#include "Behaviour/BehaviourTypes/Axon_Behaviour_Gamescene.h"

// Tools
#ifdef ASURA_TOOLS
#include "EntityTemplate/Tools_EntityTemplate_System.h"
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Asura_ServerNode_GamesceneNode
//
//////////////////////////////////////////////////////////////////////////////

Asura_Hashed_List< Asura_ServerNode_GamesceneNode > Asura_ServerNode_GamesceneNode::s_xGamesceneNodeList;

Asura_ServerNode_GamesceneNode::Asura_ServerNode_GamesceneNode(Asura_Guid uGuid)
: GAMESCENE_PARENT()
, ENTITY_PARENT( uGuid )
, m_uGamesceneNodeFlags( 0 )
, m_fMaxCoverAngleClockwise( Asura_Maths::Pi * 0.125f )
, m_fMaxCoverAngleAnticlockwise( Asura_Maths::Pi * 0.125f )
, m_fShoveOrientX( 0.f )
, m_fShoveOrientY( 0.f )
, m_uShoveType( ASURA_GAMESCENE_RAGDOLL_SHOVE_NONE )
, m_uCurrentActorGuid( ASURA_GUID_UNREGISTERED )
, m_usNodeArrivalMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
, m_usNodeDepartureMessageBlock( ASURA_STATICMESSAGE_EMPTYBLOCK )
{
    Classification = AsuraEntityClass_GamesceneNode;

    s_xGamesceneNodeList.AddToList( this );
}

Asura_ServerNode_GamesceneNode::~Asura_ServerNode_GamesceneNode()
{
    s_xGamesceneNodeList.RemoveFromList( this );
}

bool Asura_ServerNode_GamesceneNode::HandleMessage( const Asura_Message* pxMessage )
{
  //  switch ( pxMessage->GetMsgID() )
  //  {
  //      case ASURA_MSG_AXON_GAMESCENE_NEVER_STOP_AT_NODE:
  //          m_bNeverStopHere = true;
  //          // fallthrough
  //      case ASURA_MSG_AXON_GAMESCENE_FORCE_ACTOR_EXIT:
		//case ASURA_MSG_AXON_GAMESCENE_ACTOR_ATTRACT_TO_NODE:
  //      {
  //          if ( m_uCurrentActorGuid != ASURA_GUID_UNREGISTERED )
  //          {
  //              Asura_Network::Forward( pxMessage, m_uCurrentActorGuid, GetGuid() );
  //          }
  //      } return true;

		//case ASURA_MSG_AXON_GAMESCENE_ALWAYS_STOP_AT_NODE:
		//{
		//	m_bNeverStopHere = false;
		//	m_bStopHere = true;
		//} return true;

  //      default:
  //      {
  //      } return ENTITY_PARENT::HandleMessage( pxMessage );
    //}

	return ENTITY_PARENT::HandleMessage( pxMessage );
}

void Asura_ServerNode_GamesceneNode::CreateFromChunkStream( Asura_Guid uGuid, Asura_Chunk_Stream& xStream )
{
    Asura_ServerNode_GamesceneNode* pxNode = new Asura_ServerNode_GamesceneNode( uGuid );
    if ( pxNode )
    {
        pxNode->ReadFromChunkStream( xStream );
    }
}

void Asura_ServerNode_GamesceneNode::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
    int iVersion;
    xStream >> iVersion;

    // Parents.
    ENTITY_PARENT::ReadFromChunkStream( xStream );
    GAMESCENE_PARENT::ReadFromChunkStream( xStream );

    if ( iVersion == CURRENT_CHUNK_VERSION )
    {
        // Us.
        Asura_ReadFromStream_Bitfield_Wrapper< u_int > xFlagsBitfield( m_uGamesceneNodeFlags );
        xStream >> xFlagsBitfield;

        xStream >> m_fMaxCoverAngleClockwise;
        xStream >> m_fMaxCoverAngleAnticlockwise;
        xStream >> m_fShoveOrientX;
        xStream >> m_fShoveOrientY;
        xStream >> m_uShoveType;
        xStream >> m_uCurrentActorGuid;
#if defined( ASURA_USE_STREAMING ) && !defined( ASURA_TOOLS )
        m_uCurrentActorGuid	= Asura_Streaming_System::MakeCurrentMasterZoneGuid( m_uCurrentActorGuid );
#endif	// defined( ASURA_USE_STREAMING ) && !defined( ASURA_TOOLS )
        xStream >> m_usNodeArrivalMessageBlock;
        xStream >> m_usNodeDepartureMessageBlock;
    }
    else
    {
        Asura_Assertf( false, ( "Asura_ServerNode_GamesceneNode::ReadFromChunkStream - unhandled chunk version (%d)", iVersion ) );
    }
}

void Asura_ServerNode_GamesceneNode::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	// (TI - 5.9.2004) - DON'T FORGET TO UPDATE ApplyChangesForTemplateInstance IF YOU CHANGE STUFF.

	// Version
	xStream << static_cast< int >( CURRENT_CHUNK_VERSION );

	// Parent
	ENTITY_PARENT::WriteToChunkStream(xStream);
	GAMESCENE_PARENT::WriteToChunkStream(xStream);

	// Our data
    Asura_WriteToStream_Bitfield_Wrapper< u_int > xFlagsBitfield( m_uGamesceneNodeFlags );
    xFlagsBitfield.Add( m_bCanCrouchEmergeLeft,  1 );
    xFlagsBitfield.Add( m_bCanCrouchEmergeRight, 1 );
    xFlagsBitfield.Add( m_bCanCrouchEmergeUp,    1 );
    xFlagsBitfield.Add( m_bCanStandEmergeLeft,   1 );
    xFlagsBitfield.Add( m_bCanStandEmergeRight,  1 );
    xFlagsBitfield.Add( m_bLockedDueToShare,     1 );
    xFlagsBitfield.Add( m_bNeverStopHere,        1 );
    xFlagsBitfield.Add( m_bStopHere,             1 );
    xStream << xFlagsBitfield;

	xStream << m_fMaxCoverAngleClockwise;
	xStream << m_fMaxCoverAngleAnticlockwise;
	xStream << m_fShoveOrientX;
	xStream << m_fShoveOrientY;
	xStream << m_uShoveType;
	xStream << m_uCurrentActorGuid;
	xStream << m_usNodeArrivalMessageBlock;
	xStream << m_usNodeDepartureMessageBlock;

    // (TI - 5.9.2004) - DON'T FORGET TO UPDATE ApplyChangesForTemplateInstance IF YOU CHANGE STUFF.
}

void Asura_ServerNode_GamesceneNode::EnterNode( Asura_Guid uGuid )
{
	// TI (26.09.06) - 2 actors can not be at the same node at the same time
	Asura_Assertf( ( m_uCurrentActorGuid == ASURA_GUID_UNREGISTERED ) || ( uGuid == m_uCurrentActorGuid ),
				   ( "2 actors (%d and %d) at a single node (%d) at the same time?",
				     m_uCurrentActorGuid,
					 uGuid,
					 GetGuid() ) );

	m_uCurrentActorGuid = uGuid;

	if ( m_usNodeArrivalMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		// Send arrival message.
		Asura_StaticMessage_System::SendMessages( m_usNodeArrivalMessageBlock, GetGuid() );
	}
}

void Asura_ServerNode_GamesceneNode::ExitNode()
{
	Asura_Assert( m_uCurrentActorGuid != ASURA_GUID_UNREGISTERED, "No actor currently at node" );
	m_uCurrentActorGuid = ASURA_GUID_UNREGISTERED;

	if ( m_usNodeDepartureMessageBlock != ASURA_STATICMESSAGE_EMPTYBLOCK )
	{
		// Send departure message
		Asura_StaticMessage_System::SendMessages( m_usNodeDepartureMessageBlock, GetGuid() );
	}
}

void Asura_ServerNode_GamesceneNode::GetShoveDirection( Asura_Vector_3 &xShoveDirection )
{
	Asura_Euler_3 xEuler( m_fShoveOrientX, m_fShoveOrientY, 0.0f );
	Asura_Matrix_3x3 xMatrix;
	xEuler.ToMatrix( xMatrix );
	xShoveDirection.x = xMatrix.e13;
	xShoveDirection.y = xMatrix.e23;
	xShoveDirection.z = xMatrix.e33;
}

bool Asura_ServerNode_GamesceneNode::IsBaseOrDerivativeOf(u_short usClassification) const
{
	if (usClassification == AsuraEntityClass_GamesceneNode)
	{
		return true;
	}
	return ENTITY_PARENT::IsBaseOrDerivativeOf(usClassification) || GAMESCENE_PARENT::IsBaseOrDerivativeOf(usClassification);
}

#ifdef ASURA_TOOLS

void Asura_ServerNode_GamesceneNode::ApplyChangesForTemplateInstance( class Tools_EntityTemplateInstance* pxInstance )
{
	ENTITY_PARENT::ApplyChangesForTemplateInstance( pxInstance );
	GAMESCENE_PARENT::ApplyChangesForTemplateInstance( pxInstance );

	m_usNodeArrivalMessageBlock = pxInstance->ConvertMessageBlock( m_usNodeArrivalMessageBlock );
	m_usNodeDepartureMessageBlock = pxInstance->ConvertMessageBlock( m_usNodeDepartureMessageBlock );
	Asura_Euler_3 xTempEuler( m_fShoveOrientX, m_fShoveOrientY, 0.0f );
	xTempEuler = pxInstance->TransformEuler( xTempEuler );
	m_fShoveOrientX = xTempEuler.x;
	m_fShoveOrientY = xTempEuler.y;

	m_uCurrentActorGuid = pxInstance->ConvertGuid( m_uCurrentActorGuid );
}

bool Asura_ServerNode_GamesceneNode::CanBeIncludedInTemplate() const 
{
	return Classification == AsuraEntityClass_GamesceneNode;
}

void Asura_ServerNode_GamesceneNode::UpdateNeedFollowGround()
{
	//float fDistanceToIntersection;
	//if (Axon_Behaviour_Gamescene::FollowGroundTest(GetPosition(), fDistanceToIntersection))
	//{
	//	if (Asura_Maths::Abs(fDistanceToIntersection) > 0.02f)
	//	{
	//		// (AW - 12.04.2005) - Follow ground makes a difference, don't disable.
	//		m_bToolsCancelledFollowGround = false;
	//		return;
	//	}
	//}
	//// (AW - 12.04.2005) - Follow ground makes no difference.
	//m_bToolsCancelledFollowGround = true;
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

#endif // ASURA_USE_AXON
