//////////////////////////////////////////////////////////////////////////////
//
// Axon_Sense_Touch.cpp
//
// Created by NJD - 31 August 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 "Knowledge/SenseTypes/Axon_Sense_Touch.h"

// asura
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Core/Asura_Maths.h"
#include "Network/Asura_Message.h"

// axon
#include "Knowledge/Axon_Knowledge.h"
#include "Knowledge/Axon_Knowledge_System.h"
#include "Knowledge/SenseTypes/Axon_Sense_Types.h"

//////////////////////////////////////////////////////////////////////////////
//
// Axon_Sense_Touch
//
//////////////////////////////////////////////////////////////////////////////

float Axon_Sense_Touch::s_fTouchDuration = 2.0f;

Axon_Sense_Touch::Axon_Sense_Touch( Axon_Knowledge_System< Axon_Knowledge >* pxKnowledgeSystem )
: Axon_Sense< Axon_Knowledge >( pxKnowledgeSystem )
, m_fSensitivity( 0.0f )
, m_fModifier( 1.0f )
, m_xTouchList()
{
}

Axon_Sense_Touch::~Axon_Sense_Touch()
{
    DestroyAllKnowledge();
}

void Axon_Sense_Touch::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
    int iChunkVersion;
    xStream >> iChunkVersion;

    // We would do our parent chunk now, if it existed.

    if ( iChunkVersion == 0 )
    {
        xStream >> m_fModifier;
    }
    else
    {
        Asura_Assertf( false, ( "Axon_Sense_Touch::ReadFromChunkStream - unhandled chunk version (%d)", iChunkVersion ) );
    }
}

void Axon_Sense_Touch::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
    xStream << static_cast< int >( ChunkData::CURRENT_VERSION );

    // We would do our parent chunk now, if it existed.

    // Our data.
    xStream << m_fModifier;
}

void Axon_Sense_Touch::Update( const float fTimeslice )
{
    // Age the touch knowledge. Cull any that are too old.
    Asura_Hashed_List_Deleter_It< Axon_Knowledge > xTouchIter( &m_xTouchList );
    while ( !xTouchIter.Done() )
    {
        Axon_Knowledge* pxKnowledge = xTouchIter.GetCurrent();

        pxKnowledge->m_fAge += fTimeslice;
        if ( pxKnowledge->m_fAge >= s_fTouchDuration )
        {
            xTouchIter.DeleteCurrent();
            m_pxKnowledgeSystem->DestroyKnowledge( pxKnowledge );
        }
        else
        {
            xTouchIter.Next();
        }
    }
}

bool Axon_Sense_Touch::HandleMessage( const Asura_Message* pxMessage )
{
	return false;
}

void Axon_Sense_Touch::NewTouchData( const Asura_Guid uSourceGuid, const u_int uClassification,
                                     const float fDamage, const Asura_Vector_3& xPosition, const Asura_Vector_3& xDirection,
                                     const u_int uDamageType, const float fDistance /*= 0.0f*/ )
{
	// (T.I - 20.11.2007) - Make sure xDirection is a unit vector
	Asura_Assert( xDirection.Magnitude() == 1.0f, "Axon_Sense_Touch::NewTouchData - Code Bug: New touch data being created but direction has not been normalised" );

    Axon_Knowledge* pxKnowledge = m_pxKnowledgeSystem->CreateKnowledge();
	if ( pxKnowledge )
	{
		pxKnowledge->Reset();

		pxKnowledge->m_uKnowledgeID          = m_pxKnowledgeSystem->GetNewKnowledgeID();
		pxKnowledge->m_uSourceGuid           = uSourceGuid;
		pxKnowledge->m_uSourceClassification = uClassification;
		pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_TOUCH;
		pxKnowledge->m_uTypeInformation      = uDamageType;
		pxKnowledge->m_fAge                  = 0.0f;
		pxKnowledge->m_xPosition             = xPosition;
		pxKnowledge->m_xDirection            = xDirection;
		pxKnowledge->m_fDistance             = fDistance;
	}

    if ( ShouldCullTouch( *pxKnowledge ) )
    {
        m_pxKnowledgeSystem->DestroyKnowledge( pxKnowledge );
        return;
    }

    Axon_Knowledge* pxExistingKnowledge = m_xTouchList.FindObject( uSourceGuid );
    if ( pxExistingKnowledge )
    {
        m_pxKnowledgeSystem->DestroyKnowledge( pxKnowledge );

        pxExistingKnowledge->m_uTypeInformation = uDamageType;
        pxExistingKnowledge->m_fAge             = 0.0f;
        pxExistingKnowledge->m_xPosition        = xPosition;
        pxExistingKnowledge->m_xDirection       = xDirection;
		pxExistingKnowledge->m_fDistance        = fDistance;
    }
    else
    {
        m_xTouchList.AddToList( pxKnowledge );
    }
}

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

bool Axon_Sense_Touch::ShouldCullTouch( Axon_Knowledge& xKnowledge )
{
    // If we're numb we don't feel anything.
    if ( m_fSensitivity * m_fModifier == 0.0f )
    {
        return true;
    }

    return false;
}

void Axon_Sense_Touch::DestroyAllKnowledge()
{
    Asura_Hashed_List_Deleter_It< Axon_Knowledge > xTouchIter( &m_xTouchList );
    while ( !xTouchIter.Done() )
    {
        Axon_Knowledge* pxToDelete = xTouchIter.GetCurrent();
        if ( pxToDelete )
        {
            xTouchIter.DeleteCurrent();
            m_pxKnowledgeSystem->DestroyKnowledge( pxToDelete );
        }
    }
}

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

#endif
