//////////////////////////////////////////////////////////////////////////////
//
// Axon_Sense_Hearing.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_Hearing.h"

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

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

//////////////////////////////////////////////////////////////////////////////
//
// Axon_Sense_Hearing
//
//////////////////////////////////////////////////////////////////////////////

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

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

void Axon_Sense_Hearing::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_Hearing::ReadFromChunkStream - unhandled chunk version (%d)", iChunkVersion ) );
    }
}

void Axon_Sense_Hearing::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_Hearing::Update( const float fTimeslice )
{
    DestroyAllKnowledge();

    // If we're deaf we don't hear anything!
    if ( m_fSensitivity * m_fModifier == 0.0f )
    {
        return;
    }

    // Parse the sound registry and add any sounds we can hear to our own sound list.
    Asura_List_ConstIt< Axon_Sound_Registry::SoundEntry > xSoundEntryIter( &Axon_System::GetSoundRegistry()->GetEntryList() );
    while ( !xSoundEntryIter.Done() )
    {
        const Axon_Sound_Registry::SoundEntry* pxEntry = xSoundEntryIter.GetCurrent();
        xSoundEntryIter.Next();

        if ( ShouldCullSound( pxEntry ) )
        {
            continue;
        }

		// (T.I - 20.11.2007) - Direction should be a unit vector.
		Asura_Vector_3 xDirection = pxEntry->m_xPosition - m_xPosition;
		const float fDistance     = xDirection.Normalise();

        Axon_Knowledge* pxKnowledge = m_pxKnowledgeSystem->CreateKnowledge();
        if ( pxKnowledge )
        {
			pxKnowledge->m_uKnowledgeID          = m_pxKnowledgeSystem->GetNewKnowledgeID();
            pxKnowledge->m_uSourceGuid           = pxEntry->m_uSourceGuid;
            pxKnowledge->m_uSourceClassification = pxEntry->m_uClassification;
            pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_HEARING;
            pxKnowledge->m_uTypeInformation      = pxEntry->m_uSoundType;
            pxKnowledge->m_fAge                  = 0.0f;
            pxKnowledge->m_xPosition             = pxEntry->m_xPosition;
            pxKnowledge->m_xDirection            = xDirection;
			pxKnowledge->m_fDistance             = fDistance;
			pxKnowledge->m_uProjectData			 = pxEntry->m_uProjectData;

            m_xSoundList.AddToList( pxKnowledge );
        }
    }
}

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

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

bool Axon_Sense_Hearing::ShouldCullSound( const Axon_Sound_Registry::SoundEntry* pxEntry )
{
    // Cull if the sound is out of range.
    const float fEffectiveRange = pxEntry->m_fRange * m_fSensitivity * m_fModifier;
    const Asura_Vector_3& xToSound = pxEntry->m_xPosition - m_xPosition;
    if ( xToSound.MagnitudeSquared() > fEffectiveRange * fEffectiveRange )
    {
        return true;
    }

    return false;
}

void Axon_Sense_Hearing::DestroyAllKnowledge()
{
    Asura_List_It< Axon_Knowledge > xSoundListIter( &m_xSoundList );
    while ( !xSoundListIter.Done() )
    {
        Axon_Knowledge* pxToDelete = xSoundListIter.GetCurrent();
        if ( pxToDelete )
        {
            xSoundListIter.DeleteCurrent();
            m_pxKnowledgeSystem->DestroyKnowledge( pxToDelete );
        }
    }
}

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

#endif
