/* Autor: Leandro Bernsmuller
Gerencia um conjunto de agentes (seres vivos):
 cria, faz troca de dados e destroi. */



class CCenario;
class CCenarioFisico;
#include <windows.h>
#include <windowsx.h>
#include "..\princip\defs.h"
#include "dados\dados.h"
#include "dados\dadosfis.h"
#include "acoes\acao.h"
#include "agente.h"
#include "agencia.h"



/* construtor
**********************************************************/
CAgencia::CAgencia ()
{
   m_bFuncionando = FALSE;
}


  
/* Cria agentes.
poCenario - cenario que serah usado para a visualizacao dos agentes.
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CAgencia::mCriaAgentes ( CCenarioFisico* poCenario )
{
   // configuracao do agente antes de nascer
   DWORD
      adwConfiguracao [] = CONFIG_AGENTE_PRENATAL;

   // cria agentes (prepara para nascerem)
   for ( int ncA = 0; ncA < MAX_AGENTES; ncA ++ )
      // tenta alocar agente
      if ( ! m_aoAgentes [ ncA ].mCria ( adwConfiguracao, (CAgente*) &m_aoAgentes, poCenario ) )
         return FALSE;

   m_bFuncionando = TRUE;

   return TRUE;
}



/* destroi agentes (mata e desaloca)
**********************************************************/
void CAgencia::mDestroi ()
{
   if ( m_bFuncionando ) {

      // destroi agentes
      for ( int ncA = 0; ncA < MAX_AGENTES; ncA ++ ) {

         // mata agente
         m_aoAgentes [ ncA ].mTrataEvento ( NDX_EVENTO_MORRE, 0, 0 );
         // desaloca
         m_aoAgentes [ ncA ].mDestroi ();
      }

      m_bFuncionando = FALSE;
   }
}



/* Dispara um evento para todos os agentes
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CAgencia::mDisparaEvento ( DWORD dwEvento, PTRVAL pDado1, PTRVAL pDado2 )
{
   if ( m_bFuncionando ) 
      // executa
      for ( int ncA = 0; ncA < MAX_AGENTES; ncA ++ )
         if ( ! m_aoAgentes [ ncA ].mTrataEvento ( dwEvento, pDado1, pDado2 ) )
            return FALSE;

   return TRUE;
}



/* Altera a quantidade de energia do elemento do cenario
que tem o corpo especificado.
dwModeloCorpo - de qual objeto mudar a energia
fQuanto - somar que valor
**********************************************************/
void CAgencia::mAlteraEnergia ( DWORD dwModeloCorpo, float fQuanto )
{
   if ( ! m_bFuncionando )
      return;

   // altera energia de alguns agentes
   for ( int  ncA = 0; ncA < MAX_AGENTES; ncA ++ ) {

      // pega dados do agente
      CDados
         *poDadosAg = (CDados*) m_aoAgentes [ ncA ].m_poDados;

      // se nao tem informacoes fisicas, ignora ocorrencia
      if ( poDadosAg != NULL && poDadosAg->m_dwTipoDado == TIPO_FISICO ) {

         // tenta acessar dados fisicos
         CDadosFisicos
            *poDadosFisicosAg = (CDadosFisicos*) poDadosAg;

         // verifica se tem o corpo procurado
         if ( poDadosFisicosAg->m_dwTipoCorpo == dwModeloCorpo )

            // coloca energia no organismo
            poDadosFisicosAg->m_fFome += fQuanto;
      }
   }
}



/* Retorna informacoes sobre as quantidades de energia dos agentes.
retorna:
dwNumAgentes - retorna o total de agentes que possuem energia
fTotalEnergia - quantidade total de energia
fMaximoEnergia - quantidade maxima de energia que pode ser acumulada
                 pelos agentes que existem (maximo atingivel pela energia
                 total)
fMaxAbsEnergia - quantidade maxima de energia que pode ser acumulada
                 se o cenario estiver com populacao maxima
                 (maximo absoluto)
**********************************************************/
void CAgencia::mInformaEnergia ( DWORD& dwNumAgentes,
                                 float& fTotalEnergia,
                                 float& fMaximoEnergia,
                                 float& fMaxAbsEnergia )
{
   if ( ! m_bFuncionando )
      return;

   dwNumAgentes = 0;
   fTotalEnergia = 0;
   fMaximoEnergia = 0;

   // verifica cada agente
   for ( int  ncA = 0; ncA < MAX_AGENTES; ncA ++ ) {

      // pega dados do agente
      CDados
         *poDadosAg = (CDados*) m_aoAgentes [ ncA ].m_poDados;

      // se nao tem informacoes fisicas, ignora ocorrencia
      if ( poDadosAg != NULL && poDadosAg->m_dwTipoDado == TIPO_FISICO ) {

         // tenta acessar dados fisicos
         CDadosFisicos
            *poDadosFisicosAg = (CDadosFisicos*) poDadosAg;

         // modelos que devem entrar no calculo
         switch ( poDadosFisicosAg->m_dwTipoCorpo ) {

            case NDX_MODELO_PEIXE_GORDO:
            case NDX_MODELO_PEIXE_AZUL:
            case NDX_MODELO_PEIXE_LISTRADO:
               fTotalEnergia += poDadosFisicosAg->m_fFome;
               fMaximoEnergia += TX_INICIAL_FOME;
               dwNumAgentes ++;
               break;

            case NDX_MODELO_MICROORGANISMO:
            case NDX_MODELO_ALGA_VERDE:
               fTotalEnergia += poDadosFisicosAg->m_fFome;
               fMaximoEnergia += TX_MAXIMO_ABSORVE_ALIMENTO;
               dwNumAgentes ++;
               break;

            case NDX_MODELO_FUNDO_LAGO_INVISIVEL:
            case NDX_MODELO_AGUA_INVISIVEL:
               // somente se tem energia
               if ( poDadosFisicosAg->m_fFome > 0 ) {
                  fTotalEnergia += poDadosFisicosAg->m_fFome;
                  fMaximoEnergia += TX_INICIAL_FOME;
                  dwNumAgentes ++;
               }
               break;
         }
      }
   }

   // calcula maximo absoluto
   fMaxAbsEnergia = ( 3 * TX_INICIAL_FOME +              // peixes
                      2 * TX_MAXIMO_ABSORVE_ALIMENTO ) * // plantas e
                                                         // organismos
                      MAX_AGENTES_SEMELHANTES +
                      2 * TX_INICIAL_FOME;               // fundo e agua
}
