#include <cmph.h>
#include <string.h>

#define DICT_STEP 10000
#define DICWORD_LENGTH 32

#pragma pack(1)
typedef struct {
  char word[DICWORD_LENGTH];   /*  Dictionary word  */
  char tag[DICWORD_LENGTH];   /*  Corresponding tag  */
  int max_length;  /*  Length of the longest word  */
} dictionary_t;
#pragma pack(0)

dictionary_t *load_from_file (const char *filename, unsigned int totlines);

dictionary_t *load_from_file (const char *filename, unsigned int totlines) {
  dictionary_t *d, *dd;
  unsigned int dict_length, line_counter;
  FILE *pf;
  if (totlines != 0) dict_length = totlines;
  else dict_length = DICT_STEP;

  pf = fopen (filename, "r");
  if (pf == NULL) return NULL;  
  d = (dictionary_t *) malloc (dict_length * sizeof (dictionary_t));
  if (d == NULL) return d;
  line_counter = 0;
  while (!feof (pf)) {
    if (line_counter >= dict_length) {
      dict_length += DICT_STEP;
      dd = (dictionary_t *) realloc (d, dict_length * sizeof (dictionary_t));
      if (dd == NULL) return NULL;
      d = dd;
    }
    fscanf (pf , "%[^\t]\t%[^\t]\t%d\n", d[line_counter].word, d[line_counter].tag, &d[line_counter].max_length);
    line_counter ++;
  }
  fclose (pf);
  d = (dictionary_t *) realloc (d, (line_counter + 1) * sizeof (dictionary_t));
  d[line_counter].word[0] = '\0';
  d[line_counter].tag[0] = '\0';
  d[line_counter].max_length = 0;
  return d;
}

int main(int argc, char **argv)
{   
  unsigned int i, hash_index;  
  dictionary_t *dict;
  dictionary_t **sort_dict;
  unsigned int nkeys;
  cmph_io_adapter_t *source;
  FILE* mphf_fp, *sd_fp;
  cmph_config_t *config;
  cmph_t *hash;
  char buff[236];

  sprintf (buff, "%s.txt", argv[1]);
  dict = load_from_file (buff, 0);  /*  Load keys  */
  for (nkeys = 0; dict[nkeys].max_length != 0; nkeys ++);  /*  Count keys  */

  /*  Create minimal perfect hash function using the BDZ algorithm.*/
  sprintf (buff, "%s.mph", argv[1]);
  mphf_fp = fopen (buff, "w");
  source = cmph_io_struct_vector_adapter (dict, (cmph_uint32) sizeof (dictionary_t), 0, 32, nkeys); 
  config = cmph_config_new (source);
  cmph_config_set_algo (config, CMPH_BDZ);
  cmph_config_set_mphf_fd (config, mphf_fp);
  hash = cmph_new (config);
  cmph_config_destroy (config);
  cmph_dump (hash, mphf_fp); 
  cmph_io_vector_adapter_destroy (source);   
  fclose (mphf_fp);

  sort_dict = (dictionary_t **) malloc (nkeys * sizeof (dictionary_t *));
  if (sort_dict == NULL) return -1;
  /*  Sort dictionary according to the hash value  */
  for (i = 0; i < nkeys; i ++) {
    hash_index = cmph_search (hash, dict[i].word, 32);
    sort_dict[hash_index] = &dict[i];
  }

  sprintf (buff, "%s.sort", argv[1]);
  sd_fp = fopen (buff, "w");
  for (i = 0; i < nkeys; i ++) {
    fprintf (sd_fp, "%s\t%s\t%d\n", sort_dict[i]->word, sort_dict[i]->tag, sort_dict[i]->max_length);
  }
  fclose (sd_fp);
  /*  Destroy hash  */
  cmph_destroy (hash);
  return 0;
}
