/* ReSCAL - Parsing of parameters
 *
 * Copyright (C) 2011-2012
 *
 * Author: Olivier Rozier <rozier@ipgp.fr>
 *
 * This file is part of ReSCAL.
 *
 * ReSCAL 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "defs.h"
#include "macros.h"
#include "param.h"

#define LG_MAX 1024 //longueur max d'une ligne dans le fichier des parametres

extern char *model_name;
extern char *bin_filename; //nom du fichier BIN
extern char *csp_filename; //nom du fichier CSP

extern int    H, L, P;           // les dimensions de la terre


int nb_params=0;    //nombre de parametres
Parametre *liste_params=NULL;  //liste des parametres

//DECLARATION D'UN PARAMETRE
void parametre(char *par_nom, char *par_usage, void *par_adr, unsigned char par_type);
// par_nom : nom du parametre
// par_usage : definition du parametre
// par_adr : adresse du parametre (en memoire)
// par_type : type du parametre : PARAM_STRING | PARAM_INT | PARAM_FLOAT | PARAM_DOUBLE


void init_liste_params()
{
  //allocation memoire
  //liste_params = (Parametre*) malloc(NB_PARAM_MAX*sizeof(Parametre));
  AllocMemory(liste_params,Parametre,NB_PARAM_MAX);
  ResetMemory(liste_params,Parametre,NB_PARAM_MAX);

  parametre("Model", "name of model", &model_name, PARAM_STRING);

  //dimensions de la Terre
  parametre("H", "height", &H, PARAM_INT);
  parametre("L", "length", &L, PARAM_INT);
  parametre("D", "depth", &P, PARAM_INT);

  //fichier TERRE
  parametre("Bin_file", "initial cellular space (binary file)", &bin_filename, PARAM_STRING);
  parametre("Csp_file", "initial cellular space (csp file)", &csp_filename, PARAM_STRING);
}


void param_usage()
{
  int i, l;

  printf("FORMAT OF PARAMETERS_FILE\n");
  printf("  <parameter> = <value>\n");
  printf("  List of parameters:\n");

  //init_liste_params();

  for(i=0; i<nb_params; i++){
    l = strlen(liste_params[i].nom);
    if (liste_params[i].is_visible) printf("    %s%s %s\n", liste_params[i].nom, (l<=2)?"\t\t":"\t", liste_params[i].usage);
  }

}

void bad_args()
{
  ErrPrintf("erreur lecture arguments\n");

  exit(-4);
}

void bad_params()
{
  ErrPrintf("erreur lecture parametres\n");

  exit(-4);
}


int read_int(char* s)
{
  if (!isdigit(s[0]) && ((s[0]!='-') || !isdigit(s[1]))) bad_args();
  return atoi(s);
}

float read_float(char* s)
{
  //LogPrintf("read_float : %s\n",s);
  if (!isdigit(s[0]) && ((s[0]!='-') || !isdigit(s[1]))) bad_args();
  return atof(s);
}

void parametre(char *par_nom, char *par_usage, void *par_adr, unsigned char par_type)
{
  liste_params[nb_params].nom = par_nom;
  liste_params[nb_params].usage = par_usage;
  liste_params[nb_params].param = par_adr;
  liste_params[nb_params].type = par_type;
  liste_params[nb_params].is_visible = 1;
  nb_params++;
  assert(nb_params < NB_PARAM_MAX);
}

void parametre_cache(char *par_nom, char *par_usage, void *par_adr, unsigned char par_type)
{
  liste_params[nb_params].nom = par_nom;
  liste_params[nb_params].usage = par_usage;
  liste_params[nb_params].param = par_adr;
  liste_params[nb_params].type = par_type;
  liste_params[nb_params].is_visible = 0;
  nb_params++;
}

void init_val_param(char *par_nom, char *par_val)
{
  int i=0;

  while ((i<nb_params) && (strcmp(liste_params[i].nom, par_nom))) i++;

  if (i<nb_params){
    switch (liste_params[i].type) {
      case PARAM_STRING:
        *(char**)liste_params[i].param = (char*) malloc(strlen(par_val)+1);
        strcpy(*(char**)liste_params[i].param, par_val);
        break;
      case PARAM_INT:
        *(int*)liste_params[i].param = read_int(par_val);
        break;
      case PARAM_FLOAT:
        *(float*)liste_params[i].param = read_float(par_val);
        break;
      case PARAM_DOUBLE:
        *(double*)liste_params[i].param = read_float(par_val);
        break;
    }
    liste_params[i].init = 1;
    LogPrintf("%s = %s\n", par_nom, par_val);
    if (!liste_params[i].is_visible) WarnPrintf("WARNING: %s\n",liste_params[i].usage);
  }
  else{
    //ErrPrintf("ERREUR : parametre inconnu - %s\n", par_nom);
    LogPrintf("WARNING: unkown parameter - %s\n", par_nom);
    //exit(-4);
  }
}

void lecture_ligne(FILE *fp, char *str)
{
  char *ptr, *ptrmax, c;

  ptr = str;
  ptrmax = str+LG_MAX;

  // on lit une ligne complete, sans les espaces
  while (!feof(fp) && (ptr<ptrmax)){
    c = fgetc(fp);
    if ((c == '\n') || (c == EOF)){
      break;
    }
    else if (c != ' '){
      *ptr++ = c;
    }
  }

  if (ptr>=ptrmax) bad_params();

  *ptr=0;
}


void lecture_parametres(char *param_file)
{
  FILE *fp;
  char *par_nom;
  char *par_val;
  char str[LG_MAX];
  char *ptr;
  int n=0;

  //initialisation de la liste des parametres du modele
  //init_liste_params();

  //LogPrintf("modele %s\n",MOD_NAME);
  LogPrintf("lecture fichier parametres : %s\n", param_file);

  fp = fopen(param_file,"r");
  if (!fp){
    ErrPrintf("erreur ouverture fichier parametres : %s\n", param_file);
    exit(-4);
  }

  while (!feof(fp)){
    *str = 0;
    lecture_ligne(fp, str);
    //LogPrintf("str=%s\n", str);
    if (*str == '#'){  //c'est un commentaire, on ne lit pas cette ligne
      //LogPrintf("commentaire ...\n");
    }
    else if (*str == 0){ //c'est une ligne vide
      //LogPrintf("ligne vide ...\n");
    }
    else {
      ptr = strchr(str,'=');
      if (ptr){
        // on decoupe la chaine str au niveau du caractere '='
        *ptr = 0;
        par_nom = str;
        par_val = ptr+1;
        init_val_param(par_nom, par_val);
        n++;
      }
      else
        bad_params();
    }
  }

  fclose(fp);

  LogPrintf("lecture_parametres : %d parametres lus\n", n);

  if (n<nb_params){
    int i=0;
    for (i=0; i<nb_params; i++)
      if (!liste_params[i].init && liste_params[i].is_visible) LogPrintf("WARNING: parameter %s not found\n", liste_params[i].nom);
  }

  //param_parse();
}

