/* Autor: Leandro Bernsmuller
Trata arquivos de dados usados para definir: configuracao, fase;
tambem cria processos */



#include <windows.h>
#include "..\princip\defs.h"
#include "arqs.h"



/* Le arquivo de configuracao
dsVeloc - velocidade de execucao do jogo
nPorcentagemUsoJanela - quanto a janela ocupa da tela
szNomeArqFaseDefault - arquivo de fase
**********************************************************/
void CarregaConfiguracao ( DWORD& dwVeloc, int& nPorcentagemUsoJanela,
                           char* szNomeArqFaseDefault )
{
   FILE
      *pstArq = fopen ( STR_ARQ_CONFIGURACAO, "rt" );

   // algum erro
   if ( pstArq == NULL )
      return;

   // velocidade para executar programa
   fscanf ( pstArq, "%d", &dwVeloc );

   // porcentagem de uso da janela principal
   fscanf ( pstArq, "%d", &nPorcentagemUsoJanela );

   // arquivo de fase
   fscanf ( pstArq, "%s", szNomeArqFaseDefault );   

   // fecha arquivo
   fclose ( pstArq );
}



/* Le um campo do arquivo com parametros.
szNomeCampo - nome do campo a ser lido (nao pode ser "!")
dwTam - tamanho da area que recebe os dados, ver pafVals
pafVals - area para guardar valores (array de floats)
os valores lidos devem ser floats e os nomes de campos strings.

retorna TRUE - leu / FALSE - nao leu ou buffer esgotado

Formato do arquivo:
<campo> <valor1> <valor2> ... <valorN> ;

Exemplos:

CAMPO_FOO 3 9 -2 0.1 ;

XYZCAMPO_BAR
   6       5
   -10.2   1 ;
**********************************************************/
BOOL CarregaValores ( char* szNomeCampo, DWORD dwTam, float* pafVals )
{
   FILE
      *pstArq = fopen ( STR_ARQ_VALORES, "rt" );

   // algum erro
   if ( pstArq == NULL ) {
      MSGSTR ( STR_ERRO_ARQPARAMETROS );
      return FALSE;
   }

   // varre arquivo procurando campo
   while ( ! feof ( pstArq ) ) {

      char
         szStr [ 300 ];

      // le campo do arquivo
      fscanf ( pstArq, "%s", szStr );

      // verifica se eh o campo procurado
      if ( strcmp ( szNomeCampo, szStr ) == 0 ) {   // achou

         // conta quantos elementos foram lidos
         DWORD
            dwLidos = 0;

         // carrega dados do campo ateh achar fim
         while ( szStr [ 0 ] != ';' && ! feof ( pstArq ) ) {

            // le valor
            fscanf ( pstArq, "%s", szStr );

            // se nao achou fim, adiciona valor
            if ( szStr [ 0 ] != ';' ) {

               dwLidos ++;
               // memoria esgotada
               if ( dwLidos > dwTam ) {
                  MSGSTR ( "BUG - muitos dados no campo" );
                  MSGSTR ( szNomeCampo );
                  fclose ( pstArq );
                  return FALSE;
               }
               
               // converte para float e adiciona no conjunto de valores
               *pafVals = atof ( szStr );
               pafVals ++;
            }
         }

         fclose ( pstArq );
         return TRUE;
      }
   }

   // fecha arquivo
   fclose ( pstArq );

   // nao leu e achou fim
   MSGSTR ( szNomeCampo );
   return FALSE;
}



/* Salva arquivo de configuracao
**********************************************************/
void SalvaConfiguracao ( DWORD dwVeloc, int nPorcentagemUsoJanela,
                         char* szNomeArqFaseDefault )
{
   FILE
      *pstArq = fopen ( STR_ARQ_CONFIGURACAO, "wt" );
   // falhou -> informa
   if ( pstArq == NULL ) {
      MSGSTR ( STR_ERRO_ARQCONFIGURACAO );
      MSGSTR ( STR_ARQ_CONFIGURACAO );
      return;
   }

   // velocidade para executar programa
   fprintf ( pstArq, "%d\n", dwVeloc );

   // porcentagem de uso da janela principal
   fprintf ( pstArq, "%d\n", nPorcentagemUsoJanela );

   // fase
   fprintf ( pstArq, "%s\n", szNomeArqFaseDefault );

   // fecha arquivo
   fclose ( pstArq );
}



/* Le arquivo de fase
szNomeArq - nome do arquivo de fase
pastEventosFase - retorna eventos lidos do arquivo
retorna TRUE - certo / FALSE - erro
**********************************************************/
BOOL CarregaFase ( char* szNomeArq, tagEventoTempo* pastEventosFase )
{
   // inicia eventos da fase (como nao ocorrendo)
   for ( DWORD dwcT = 0; dwcT < MAX_EVENTOS_FASE; dwcT ++ ) {
      // senao executados apohs o fim da partida
      pastEventosFase [ dwcT ].dwTempo = 1000000;
      // evento nulo
      pastEventosFase [ dwcT ].dwEvento = EVENTO_TMP_NULO;
   }

   // tenta carregar fase
   FILE
      *pstArq = fopen ( szNomeArq, "rt" );
   // falhou -> informa
   if ( pstArq == NULL ) {
      MSGSTR ( STR_ERRO_ARQFASE );
      MSGSTR ( szNomeArq );
      return FALSE;
   }

   // le eventos que devem ocorrer durante a fase
   DWORD
      dwPosEvento = 0;
   // le ateh o fim do arquivo ou ser lido o maximo de eventos
   while ( ! feof ( pstArq ) && dwPosEvento < MAX_EVENTOS_FASE ) {

      // le tempo em que deve ocorrer e o evento relacionado
      fscanf ( pstArq, "%d", &pastEventosFase [ dwPosEvento ].dwTempo );
      fscanf ( pstArq, "%d", &pastEventosFase [ dwPosEvento ].dwEvento );
      dwPosEvento ++;
   }

   // fecha arquivo
   fclose ( pstArq );

   // ordena os eventos cronologicamente (crescentemente)
   for ( unsigned int ucI = 0; ucI < MAX_EVENTOS_FASE; ucI ++ ) {
 
      DWORD
         dwTempoMenor = 10000000,
         dwNdxMenor = 0;

      // encontra o menor dentre os que ainda nao foram ordenados
      for ( unsigned int ucO = ucI; ucO < MAX_EVENTOS_FASE; ucO ++ ) {
      
         // se encontrou um elemento maior que o atual
         if ( dwTempoMenor >= pastEventosFase [ ucO ].dwTempo ) {
         
            dwTempoMenor = pastEventosFase [ ucO ].dwTempo;
            dwNdxMenor = ucO;
         }
         
         // coloca o menor no lugar
         
         // troca valores
         DWORD
            dwTemp = pastEventosFase [ dwNdxMenor ].dwTempo;
         pastEventosFase [ dwNdxMenor ].dwTempo = pastEventosFase [ ucI ].dwTempo;
         pastEventosFase [ ucI ].dwTempo = dwTemp;
         dwTemp = pastEventosFase [ dwNdxMenor ].dwEvento;
         pastEventosFase [ dwNdxMenor ].dwEvento = pastEventosFase [ ucI ].dwEvento;
         pastEventosFase [ ucI ].dwEvento = dwTemp;
      }
   }

   return TRUE;
}


  
/* Executa um processo (programa)
szComando - linha de comando a executar
stProc - retorna informacoes sobre o processo criado
**********************************************************/
void ExecutaProcesso ( char* szComando, PROCESS_INFORMATION& stProc )
{
   STARTUPINFO
      stIniInfo; // informacao inicial para o processo

   stIniInfo.cb = sizeof ( STARTUPINFO );
   stIniInfo.lpReserved = NULL;
   stIniInfo.lpDesktop = NULL;
   stIniInfo.lpTitle = NULL;
   stIniInfo.dwFlags = STARTF_USESHOWWINDOW;      // informa que atributo estah em alteracao
   stIniInfo.cbReserved2 = 0;
   stIniInfo.lpReserved2 = NULL;
   stIniInfo.wShowWindow = SW_SHOWNOACTIVATE;     // mostra janela criada passar foco para ela

   // cria processo
   BOOL
      bRes;
   bRes = CreateProcess (
      NULL, // arquivo executavel - se NULL entao ser proximo parametro
      szComando, // linha de comando com parametros a serem passados
      NULL, // atributos de seguranca para o processo, soh vale para NT, ou outros que tenham seguranca
      NULL, // atributos de seguranca para a thread principal, soh vale para NT, ou outros que tenham seguranca
      FALSE, // T - alcas do processo pai serao herdadas para o filho, F - nao serao
      0, // forma como o processo serah processado (aplictivos == 0)
      NULL, // ponteiro para buffer que possui variaveis do ambiente que serao usadas (NULL usa as do pai)
      NULL, // drive e diretorios atuais (de trabalho) do processo filho
      &stIniInfo, // STARTUPINFO
      &stProc  ); // informacao sobre o processo
}



/* Se um determanado processo ainda estah rodando
stProc - qual processo testar
retorna TRUE - sim / FALSE - nao
**********************************************************/
BOOL ProcessoRodando ( PROCESS_INFORMATION &stProc )
{
   DWORD
      dwCod;

   // pega codigo de termino do processo
   ::GetExitCodeProcess ( stProc.hProcess, &dwCod );

   // verifica se codigo indica que processo nao terminou
   if ( dwCod == STILL_ACTIVE )
      return TRUE;

   return FALSE;
}
