/* -*- c-file-style: "GNU" -*- */
/*
 * Copyright (C) CNRS, INRIA, Universite Bordeaux 1, Telecom SudParis
 * See COPYING in top-level directory.
 */

#include <stdio.h>

#include "ev_codes.h"
#include "eztrace_convert_core.h"
#include "eztrace_list.h"
#include "eztrace_convert.h"
#include "eztrace_convert_core.h"
#include "eztrace_hook.h"
#include "eztrace_stats_core.h"
#include "eztrace_litl.h"

char* output_path = NULL;

static struct eztrace_archive_info *arch_info = NULL, *arch_info_head = NULL;

static void usage(int argc __attribute__((unused)), char **argv) {
  fprintf(stderr, "Usage : %s [-v] input_filename input_filename ... \n",
	  argv[0]);
}

static void parse_args(int argc, char **argv) {
  int i;
  litl_size_t j;
  litl_read_trace_t* arch;
  struct eztrace_archive_info *tmp;

  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-v") == 0) {
      VERBOSE = 1;
    } else if (strcmp(argv[i], "-o") == 0) {
      output_path = argv[++i];
    } else if (strcmp(argv[i], "-h") == 0) {
      usage(argc, argv);
      exit(-1);
    } else {
      /* count the number of traces including those in archives */

      /* open the trace file. Do this here to deal with archives of traces */
      arch = litl_read_open_trace(argv[i]);
      if (!arch) {
	perror("litl_read_open_trace:");
	exit(-1);
      }

      tmp = (struct eztrace_archive_info *) malloc(sizeof(struct eztrace_archive_info));
      tmp->block = arch;
      tmp->filename = argv[i];
      tmp->next = NULL;

      if (arch_info == NULL ) {
	arch_info = tmp;
	arch_info_head = arch_info;
      } else {
	arch_info->next = tmp;
	arch_info = arch_info->next;
      }

      NB_TRACES += tmp->block->nb_processes;
    }
  }

  if (NB_TRACES < 1) {
    usage(argc, argv);
    exit(-1);
  }

  /* create and initialize traces */
  j = 0;
  arch_info = arch_info_head;
  eztrace_convert_init(NB_TRACES);
  while (arch_info != NULL ) {
    tmp = arch_info;
    arch_info = arch_info->next;
    arch = tmp->block;
    // init traces
    for (i = 0; i < tmp->block->nb_processes; i++) {
      get_traces(i + j)->input_filename = tmp->filename;
      get_traces(i + j)->block = tmp->block;
      get_traces(i + j)->trace_index = i;
    }
    litl_read_init_processes(arch);
    j += tmp->block->nb_processes;
  }
}

static void __clean_up() {
  while (arch_info_head != NULL) {
    arch_info = arch_info_head;
    arch_info_head = arch_info_head->next;
    free(arch_info);
  }
}

/*
 * This program should be used to parse the log file generated by LiTL
 */
int main(int argc, char **argv) {
  set_cur_mode(EZTRACE_STATS);

  asprintf(&output_path, "./eztrace_stats_%s", getenv("USER"));
  eztrace_stats_set_output_dir(output_path);

  load_modules(1);

  /* parse the arguments passed to this program */
  parse_args(argc, argv);

  if (!output_path)
    asprintf(&output_path, "./eztrace_stats_%s", getenv("USER"));
  eztrace_stats_set_output_dir(output_path);

  __init_modules();

  int i;
  /* initialize the traces array */
  for (i = 0; i < NB_TRACES; i++) {
    /* open the trace file */

    get_traces(i)->delay = 0;
    get_traces(i)->rank = i;
    get_traces(i)->id = i;
    get_traces(i)->done = 0;
    get_traces(i)->skip = 0;

    eztrace_create_containers(i);

    /* if several traces are loaded, this means that MPI was used,
     * so let's skip all the first events until MPI_Init is detected
     */
    if (NB_TRACES > 1)
      get_traces(i)->start = 0;
    else {
      CREATE_TRACE_ID_STR(get_traces(i)->trace_id, 0);
      get_traces(i)->start = 1;
      NB_START = 1;
      eztrace_create_ids(get_traces(i)->rank);
    }

    ezt_litl_read_next_event(get_traces(i));
    get_traces(i)->start_time = LITL_READ_GET_TIME(&get_traces(i)->ev);
  }

  /* todo: 0 or i ? */
  set_cur_trace(get_traces(0));
  set_cur_ev(&get_traces(i)->ev);

  struct eztrace_event_handler* handler_info = get_handler_info();

  /* OK, let's work ! */
  while (handler_info->nb_done < NB_TRACES) {
    set_cur_mode(EZTRACE_STATS);
    handle_one_event(NULL);
  }

  /* finally, call the print_stats callback for all plugins */
  __print_stats();
  __clean_up();

  return 0;
}
