/*
 * This file is part of MAMMULT: Metrics And Models for Multilayer Networks
 *  
 * This program 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 3 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, see .
*/
#include "iltree.h"
#include 
#include 
#include 
#include 
#include "utils.h"
void* alloc_double(){
  return malloc(sizeof(long double));
}
void dealloc_double(void *elem){
  free(elem);
}
void copy_double(void *elem1, void *elem2){
  *((long double*)elem2) = *((long double*)elem1);
}
int compare_double(void *elem1, void *elem2){
  return *((long double*)elem1) - *((long double*)elem2);
}
void print_double(void *elem, void *fileout){
  
  long double k, i, j;
  long double x;
  k = *((long double*)elem);
  x = (1 + sqrtl(1 + 8 * (k-1))) / 2;
  i = floorl(x) + 1;
  j = k - ( (i-1)*1.0 * (i-2) ) /2;
  //printf("x: %Lf\n i: %0.0Lf j: %0.0Lf\n", x, i, j);
  fprintf((FILE*)fileout, "%0.0Lf %0.0Lf\n", i-1, j-1);
}
iltree_t init_tree(iltree_t t, void *fileout){
  
  ilfunc_t funs= {
    .alloc = alloc_double,
    .dealloc = dealloc_double, 
    .copy = copy_double,
    .compare = compare_double, 
    .print = print_double,
    .fileout = fileout
  };
  
  t = iltree_create(t);
  iltree_set_funs(t, &funs);
  return t;
}
/* @@@@ CAMBIARE IL PRIMO PARAMETRO IN UN FILE* PER RENDERLA COERENTE
   ALLE ALTRE FUNZIONI DI READ!!!!*/
int read_deg_distr(FILE *filein, unsigned int **degs, unsigned int **Nk, double **p){
  
  int n_degs = 0;
  int size = 10;
  char *line;
  char buff[256];
  int k_i, num_i;
  double p_i;
  char *ptr;
  line = NULL;
  *degs = realloc(*degs, size*sizeof(unsigned int));
  *Nk = realloc(*Nk, size*sizeof(unsigned int));
  *p = realloc(*p, size*sizeof(double));
  
  while(fgets(buff, 256, filein)){
    ptr = strtok(buff, " ");
    if (ptr[0] == '#')
      continue;
    k_i = atoi(ptr);
    ptr = strtok(NULL, " " );
    num_i = atoi(ptr);
    ptr = strtok(NULL, " \n");
    p_i = atof(ptr);
    if (n_degs == size){
      size += 10;
      *degs = realloc(*degs, size*sizeof(unsigned int));
      *Nk = realloc(*Nk, size*sizeof(unsigned int));
      *p = realloc(*p, size*sizeof(double));
    }
    (*degs)[n_degs] = k_i;
    (*Nk)[n_degs] = num_i;
    (*p)[n_degs] = p_i;
    n_degs += 1;
  }
  *degs = realloc(*degs, n_degs*sizeof(unsigned int));
  *Nk = realloc(*Nk, n_degs*sizeof(unsigned int));
  *p = realloc(*p, n_degs*sizeof(double));
  return n_degs;
}
int read_deg_seq(FILE *filein, unsigned int **nodes){
  int size, N, k;
  char buff[256];
  char *ptr;
  N = 0;
  size = 10;
  
  *nodes = (unsigned int*)malloc(size * sizeof(unsigned int));
  while(fgets(buff, 256, filein)){
    ptr = strtok(buff, " ");
    if (ptr[0] == '#')
      continue;
    k = atoi(ptr);
    
    if (N == size){
      size += 10;
      *nodes = realloc(*nodes, size*sizeof(unsigned int));
    }
    (*nodes)[N] = k;
    N += 1;
  }
  *nodes = realloc(*nodes, N * sizeof(unsigned int));
  return N;
}
int read_stubs(FILE *filein, unsigned int **S){
  
  int size, K;
  char buff[256];
  char *ptr;
  
  K=0;
  size = 20;
  *S = malloc(size * sizeof(unsigned int));
  
  while(fgets(buff, 256, filein)){
    if (K == size){
      size += 20;
      *S = realloc(*S, size*sizeof(unsigned int));
    }
    ptr = strtok(buff, " "); /* read the first node */
    (*S)[K++] = atoi(ptr);
    ptr = strtok(NULL, " "); /* read the second node */
    (*S)[K++] = atoi(ptr);
  }
  *S = realloc(*S, K * sizeof(unsigned int));
  return K;
}
/*
 * Read a file in ij format 
 */
int read_ij(FILE *filein, unsigned int **I, unsigned int **J){
  
  unsigned int size, K;
  char buff[256];
  char *ptr;
  
  size = 20;
  K = 0;
  
  *I = malloc(size * sizeof(unsigned int));
  *J = malloc(size * sizeof(unsigned int));
  while(fgets(buff, 256, filein)){
    if (buff[0] == '#')
      continue;
    if (K == size){
      size += 20;
      *I = realloc(*I, size*sizeof(unsigned int));
      *J = realloc(*J, size*sizeof(unsigned int));
    }
    ptr = strtok(buff, " "); /* read the first node */
    (*I)[K] = atoi(ptr);
    ptr = strtok(NULL, " "); /* read the second node */
    (*J)[K] = atoi(ptr);
    K += 1;
  }
  
  *I = realloc(*I, K * sizeof(unsigned int));
  *J = realloc(*J, K * sizeof(unsigned int));
  return K;
}
/*funzione pesata di moreno*/
int read_ij_w(FILE *filein, unsigned int **I, unsigned int **J , double **W){
  
  unsigned int size, K;
  char buff[256];
  char *ptr;
  
  size = 20;
  K = 0;
  
  *I = malloc(size * sizeof(unsigned int));
  *J = malloc(size * sizeof(unsigned int));
  *W = malloc(size * sizeof(double));
  
  while(fgets(buff, 256, filein)){
    if (buff[0] == '#')
      continue;
    if (K == size){
      size += 20;
      *I = realloc(*I, size*sizeof(unsigned int));
      *J = realloc(*J, size*sizeof(unsigned int));
      *W = realloc(*W, size*sizeof(double));
      if (*W==NULL) {
	printf ("Errore");
	exit(-1);
	}
    }
    ptr = strtok(buff, " "); /* read the first node */
    (*I)[K] = atoi(ptr);
    ptr = strtok(NULL, " "); /* read the second node */
    (*J)[K] = atoi(ptr);
    ptr = strtok(NULL, " "); /* read the weight  */
    (*W)[K] = atof(ptr);    
    K += 1;
  }
  
  *I = realloc(*I, K * sizeof(unsigned int));
  *J = realloc(*J, K * sizeof(unsigned int));
  *W = realloc(*W, K * sizeof(double));
  return K;
}
void read_slap(FILE *filein, unsigned int *K, unsigned int *N, 
              unsigned int **J_slap, unsigned int **r_slap){
  
  unsigned int *I=NULL, *J=NULL;
  unsigned int i, k;
  
  k = read_ij(filein, &I, &J);
  *K = 2 * k;
  I = realloc(I, 2*k * sizeof(unsigned int));
  J = realloc(J, 2*k * sizeof(unsigned int));
  for (i=k; i<2*k; i ++){
    I[i] = J[i-k];
    J[i] = I[i-k];
  }
  
  *N = convert_ij2slap(I, J, 2*k, r_slap, J_slap);
  free(I);
  free(J);
  return;
}
/*funzione pesata di moreno*/
void read_slap_w(FILE *filein, unsigned int *K, unsigned int *N, 
              unsigned int **J_slap, unsigned int **r_slap, double **w_slap){
  
  unsigned int *I=NULL, *J=NULL;
  double *W=NULL;
  unsigned int i, k;
  
  k = read_ij_w(filein, &I, &J, &W);
  *K = 2 * k;
  I = realloc(I, 2*k * sizeof(unsigned int));
  J = realloc(J, 2*k * sizeof(unsigned int));
  W = realloc(W, 2*k * sizeof(double));
  
  for (i=k; i<2*k; i ++){
    I[i] = J[i-k];
    J[i] = I[i-k];
    W[i] = W[i-k];
  }
  
  *N = convert_ij2slap_w(I, J, W, 2*k, r_slap, J_slap, w_slap);
  free(I);
  free(J);
  free(W);
  return;
}
unsigned int find_max(unsigned int *v, unsigned int N){
  unsigned int i, max;
  
  max = v[0];
  i = 0;
  while(++i < N){
    if (v[i] > max)
      max = v[i];
  }
  return max;
}
int convert_ij2slap(unsigned int *I, unsigned int *J, unsigned int K, 
                    unsigned int ** r_slap, unsigned int **J_slap){
  
  unsigned int tmp, max;
  unsigned int N;
  unsigned int i, pos;
  unsigned int *p;
  max = find_max(I, K) + 1;
  tmp = find_max(J, K) + 1;
  if (tmp > max){
    max = tmp ;
  }
  
  *r_slap = malloc( (max+1) * sizeof(unsigned int));
  p = malloc(max * sizeof(unsigned int));
  
  *J_slap = malloc(K * sizeof(unsigned int));
  
  memset(*r_slap, 0, (max+1) * sizeof(unsigned int));
  for(i=0; i max){
    max = tmp ;
  }
  
  *r_slap = malloc( (max+1) * sizeof(unsigned int));
  p = malloc(max * sizeof(unsigned int));
  
  *J_slap = malloc(K * sizeof(unsigned int));
  *w_slap = malloc(K * sizeof(double));
  
  memset(*r_slap, 0, (max+1) * sizeof(unsigned int));
  for(i=0; i i){
        fprintf(fileout, "%d %d\n", i, J_slap[j]);
      }
    }
  }
}
  
/* Check if j is a neighbour of i */
int is_neigh(unsigned int *J_slap, unsigned int *r_slap, unsigned int N, 
             unsigned int i, unsigned int j){
  
  unsigned int l;
  unsigned int count;
  count = 0;
  for(l=r_slap[i]; l