/*
Copyright (C) by Dmitry E. Oboukhov 2006, 2007

  This package is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  
  This package is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this package; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
*/
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <stdlib.h>
/* #include <malloc.h> */
#include <stdio.h>
#include "unit.h"
#include "units_info.h"
#include "parse_input.h"
#include "version.h"

unit *attacker, *defender;

#define BUF_SIZE  16384



//===================================================================
// читает входной поток данных
//===================================================================
static void read_task(FILE * in, sim_info * sinfo)
{
  // читаем весь ввод в буффер
  // (задача не может быть больше 
  char *buffer=calloc(sizeof(char), BUF_SIZE);
  fread(buffer, BUF_SIZE, sizeof(char), in);
  
  sinfo->defender_resource.metal=0;
  sinfo->defender_resource.crystal=0;
  sinfo->defender_resource.deut=0;
  
  int i;

  // преобразуем все строки в Z-завершенные
  for (i=0; i<BUF_SIZE; i++)
  {
    switch(buffer[i])
    {
      case '\n':
      case '\r': buffer[i]=0;   break;
      case '\t': buffer[i]=' '; break;
    }
  }

  // что в данный момент парсим
  // 0 - атакующий
  // 1 - обороняющийся
  int what=0; 
  // атакующийся и защищающийся игроки
  gamer_info gamer[2];
  memset(gamer+0, 0, sizeof(gamer_info));
  memset(gamer+1, 0, sizeof(gamer_info));
  
  // парсим строки
  for (i=0; i<BUF_SIZE; i++)
  {
    // изначально считаем что мы в начале строки

    // убираем пробелы в начале строки
    while(buffer[i]==' ') strcpy(buffer+i, buffer+i+1);

    // пропускаем пустые строки
    int slen=strlen(buffer+i); if (!slen) continue;
    int el=slen-1;

    // удаляем пробелы в конце строки
    for (el=slen-1; el>=0; el--)
    {
      if(buffer[i+el]!=' ') break;
      buffer[i+el]=0;
    }

    // если вся строка удалилась то и хрен с ней
    if (*buffer==0) { i+=slen; continue; }

    // переключение контекста на атакующего
    if (strcasecmp(buffer+i, "attacker")==0)
    {
      what=0;
    }
    // переключение контекста на защитника
    else if (strcasecmp(buffer+i, "defender")==0)
    {
      what=1;
    }
    // строки вида key = value
    else 
    {
      // выделяем ключ и значение
      char *key=buffer+i;
      char *value=strchr(key, '=');

      // если строка имеет правильный формат
      if (value)
      {
        // удаляем возможные пробелы в конце ключа
        for (el=value-key-1; el>=0; el--)
        {
          if(key[el]!=' ') break;
          buffer[i+el]=0;
        }
        // удаляем пробелы в начале значения
        *value++=0; while(*value==' ') value++;


        // значение должно быть целым, неотрицательным числом
        int ivalue=atoi(value);
        if (ivalue<0) { i+=slen; continue; }
        
        // атака игрока
        if (strcasecmp(key, "attack")==0)
        {
          gamer[what].attack=ivalue;
        }
        // щиты игрока
        else if (strcasecmp(key, "shield")==0)
        {
          gamer[what].shield=ivalue;
        }
        // броня игрока
        else if (strcasecmp(key, "armory")==0)
        {
          gamer[what].armory=ivalue;
        }
        else if (strcasecmp(key, "metal")==0)
        {
          sinfo->defender_resource.metal=ivalue;
        }
        else if (strcasecmp(key, "crystal")==0)
        {
          sinfo->defender_resource.crystal=ivalue;
        }
        else if (strcasecmp(key, "deut")==0)
        {
          sinfo->defender_resource.deut=ivalue;
        }
        // корабли игрока
        else
        {
          int uno;
          for (uno=0; uno<UNITS_COUNT; uno++)
          {
            // кораблик
            if (strcasecmp(key, units[uno].name)==0)
            {
              gamer[what].unit[uno]+=ivalue;
              gamer[what].count+=ivalue;
              break;
            }
          }
        }
      }
    }
    i+=slen;
  }
  free(buffer);

  sinfo->attacker=gamer[0];
  sinfo->defender=gamer[1];
}

//===================================================================
// парсит входной поток (или читает указанный в аргументах файл)
//===================================================================
sim_info * parse_input(int argc, char ** argv)
{
  int c;
  char *file_input=0;
  char *file_output=0;

  sim_info *sim=calloc(sizeof(sim_info), 1);
  memset(sim, 0, sizeof(sim_info));
  sim->simulations=100;
  
  sim->work_time=0;
  sim->forks_count=0;
  
  for (c=0; c!=-1; c=getopt(argc, argv, "i:o:s:ht:V"
#ifndef __WIN32__
        "f:"
#endif
        ))
  {
    switch(c)
    {
      case 'V':
        printf("%s\n", VERSION);
        exit(0);

      case 'i':
        file_input=optarg;
        break;
      case 'o':
        file_output=optarg;
        break;
      case 't':
        sim->work_time=atoi(optarg);
        if (sim->work_time<0) 
        {
          fprintf(stderr, "Illegal value for option -t: '%s'\n", optarg);
          sim->work_time=0;
        }
        break;

#ifndef __WIN32__
      case 'f':
        sim->forks_count=atoi(optarg);
        if (sim->work_time<0 || sim->work_time>100)
        {
          fprintf(stderr, "Illegal value for option -f: '%s'\n", optarg);
          sim->forks_count=0;
        }
        break;
#endif
      
      case '?':
      case 'h':
        fprintf(stderr,
            "Usage: ./csim [ -i input_file ] [ -o output file ]\n"
            "              [ -s iterations ] [ -t seconds work]\n"
#ifndef __WIN32__
            "              [ -f forks_count ]\n"
#endif
            " 1 <= iterations <= N (0 == 100 iterations)\n"
            " 0 <= seconds work <= N (0 == no limits)\n"
#ifndef __WIN32__
            " 0 <= forks_count <= 100\n"
#endif
            " if input_file is not defined, use STDIN\n"
            " if output_file is not defined, use STDOUT\n"
            " if iterations is not defined, use 100 iterations\n"
            " -V - get version\n"
        );
        exit(0);
      case 's':
        sim->simulations=atoi(optarg);
        if (!sim->simulations)
        {
          fprintf(stderr, "Illegal value for option -s: '%s'\n", optarg);
          exit(4);
        }
        break;
    }
  }

  // вывод в определенный файл
  if (file_output)
  {
    FILE *output=fopen(file_output, "wt");
    if (!output)
    {
      fprintf(stderr, "Can not open file '%s': %s\n",
          file_output, strerror(errno));
      exit(1);
    }
    dup2(fileno(output), fileno(stdout));
  }

  printf( "GNU Ogame console simulator v" VERSION ", "
          "(cl) by Dmitry E. Oboukhov <dimka@uvw.ru>\n\n"
          "usage '%s -h' for help\n\n", argv[0]);
    
  
  // если файл определен в комстроке
  // то используем его вместо stdin
  if (file_input)
  {
    FILE * input=fopen(file_input, "rt");
    if (!input)
    {
      fprintf(stderr, "Can not open file '%s': %s\n",
          file_input, strerror(errno));
      exit(2);
    }
    read_task(input, sim);
    fclose(input);
  }
  else
  {
    read_task(stdin, sim);
  }

  return sim;
}
//===================================================================
