#include "dsut.h"
#include "ammarep.h"

void d2s_main(int argc,char *argv[])
{
  datset *ds = mk_datset_from_argc_argv(argc,argv);
  int r;

  for ( r = 0 ; r < ds_num_rows(ds) ; r++ )
  {
    int a;
    for ( a = 0 ; a < ds_num_atts(ds) ; a++ )
    {
      int v = ds_symbol_ref(ds,r,a);
      if ( v == 1 )
	printf("%d,%s\n",r,ds_attnum_to_name(ds,a));
    }
  }

  free_datset(ds);
}

bool is_p1_attnum(datset *mds,int attnum)
{
  char *name = ds_attnum_to_name(mds,attnum);
  return name[2] == '-';
}

bool someone_is_missing(datset *mds,int row,int attnum)
{
  bool result = FALSE;
  while ( !result && !is_p1_attnum(mds,attnum) )
  {
    if ( ds_value_is_missing(mds,row,attnum) )
      result = TRUE;
    else
      attnum = attnum-1;
  }
  result = result || ds_value_is_missing(mds,row,attnum);
  return result;
}

double recent_p1_value(datset *mds,int row,int attnum)
{
  while ( !is_p1_attnum(mds,attnum) )
    attnum = attnum - 1;
  return ds_real_ref(mds,row,attnum);
}

dyv *mk_p1_dyv(datset *mds,int row)
{
  int attnum;
  dyv *d = mk_dyv(0);
  for ( attnum = 1 ; attnum < ds_num_atts(mds) ; attnum++ )
  {
    if ( !ds_value_is_missing(mds,row,attnum) && is_p1_attnum(mds,attnum) )
      add_to_dyv(d,ds_real_ref(mds,row,attnum));
  }
  return d;
}

dyv *mk_other_dyv(datset *mds,int row)
{
  int attnum;
  dyv *d = mk_dyv(0);
  for ( attnum = 1 ; attnum < ds_num_atts(mds) ; attnum++ )
  {
    if ( !ds_value_is_missing(mds,row,attnum) && !is_p1_attnum(mds,attnum) )
      add_to_dyv(d,ds_real_ref(mds,row,attnum));
  }
  return d;
}

dyv *mk_gm_dyv(datset *mds,int row)
{
  int attnum;
  dyv *d = mk_dyv(0);
  for ( attnum = 1 ; attnum < ds_num_atts(mds) ; attnum++ )
  {
    if ( !ds_value_is_missing(mds,row,attnum) )
      add_to_dyv(d,ds_real_ref(mds,row,attnum));
  }
  return d;
}

/*
slope = [sum_i (y_i - y_base) (x_i - x_base)] / [sum_i (x_i - x_base)^2]
where in this case x_i = i, x_base = 0 
*/
double dyv_slope(dyv *d)
{
  double y_base = dyv_min(d);
  int i;
  double num = 0.0;
  double den = 0.0;
  for ( i = 0 ; i < dyv_size(d) ; i++ )
  {
    double x_i = (double) i;
    double x_base = 0.0;
    double y_i = dyv_ref(d,i);
    den += (x_i - x_base) * (x_i - x_base);
    num += (y_i - y_base) * (x_i - x_base);
  }
  return num / den;
}

void fprint_dyv_stats(FILE *s,dyv *d)
{
  fprintf(s,"%8.3f,%8.3f,%8.3f,%8.3f,%8.3f,%3d",
          dyv_mean(d),
          dyv_sdev(d),
          dyv_min(d),
          dyv_max(d),
          dyv_slope(d),
          dyv_size(d));
}

void db(void)
{
/*  printf("\n");
  wait_for_key();
*/
}

void fprint_biggy_row(FILE *s,datset *pds,datset *mds,int row,int attnum)
{
  if ( !someone_is_missing(mds,row,attnum) && !is_p1_attnum(mds,attnum) )
  {
    double rp1 = recent_p1_value(mds,row,attnum);
    double thisp = ds_real_ref(mds,row,attnum);
    char *name = mk_copy_string(ds_attnum_to_name(mds,attnum));
    dyv *cat_p1_dyv = mk_p1_dyv(mds,row);
    double p1mean = dyv_mean(cat_p1_dyv);
    dyv *cat_other_dyv = mk_other_dyv(mds,row);
    double othmean = dyv_mean(cat_other_dyv);
    dyv *cat_gm_dyv = mk_gm_dyv(mds,row);
    double mean_intake = dyv_mean(cat_gm_dyv);
    int i;
    int pds_row;

    name[0] = '0';
    pds_row = atoi(name) - 2;
    fprintf(s,"c%d,%6s,",my_irint(ds_real_ref(mds,row,0)),ds_attnum_to_name(mds,attnum));
    db();
    fprintf(s,"%3d,%3d,%3d,%8.5f,%8.3f,%8.3f,%8.5f,",
            my_irint(thisp),
            my_irint(rp1),my_irint(thisp-rp1),thisp/real_max(1e-20+0.5*thisp,rp1),
            mean_intake,thisp - mean_intake,thisp/real_max(1e-20+0.5*thisp,mean_intake));
    fprintf(s,"%8.3f,%8.5f,",
            thisp - p1mean,thisp/real_max(1e-20+0.5*thisp,p1mean));
    fprintf(s,"%8.3f,%8.5f,",
            thisp - othmean,thisp/real_max(1e-20+0.5*thisp,othmean));
    db();
    for ( i = 1 ; i < ds_num_atts(pds) ; i++ )
      fprintf(s,"%8s,",ds_row_attnum_to_name(pds,pds_row,i));
    db();
    fprint_dyv_stats(s,cat_p1_dyv);
    fprintf(s,",");
    db();
    fprint_dyv_stats(s,cat_other_dyv);
    fprintf(s,",");
    db();
    fprint_dyv_stats(s,cat_gm_dyv);
    db();
    fprintf(s,"\n");
    free_dyv(cat_p1_dyv);
    free_dyv(cat_other_dyv);
  }
}

void fprint_biggy_attnames(FILE *s,datset *pds)
{
  int i;
  fprintf(s,"catid,productid,");
  fprintf(s,"intake,recentp1,p1diff,p1ratio,mean,meandiff,meanratio,");
  fprintf(s,"p1meandiff,p1meanratio,");
  fprintf(s,"omdiff,omratio,");
  for ( i = 1 ; i < ds_num_atts(pds) ; i++ )
    fprintf(s,"%8s,",ds_attnum_to_name(pds,i));
  for ( i = 0 ; i <= 2 ; i++ )
  {
    char *base = (i==0)?"p1":(i==1)?"other":"all";
    fprintf(s,"%smean,%ssdev,%smin,%smax,%sslope,%ssize",
            base,base,base,base,base,base);
    if ( i < 2 ) fprintf(s,",");
  }
  fprintf(s,"\n");
}

void fprint_biggy(FILE *s,datset *pds,datset *mds)
{
  int row;
  int attnum;
  fprint_biggy_attnames(s,pds);
  for ( row = 0 ; row < ds_num_rows(mds) ; row++ )
  {
    dyv *cat_p1_dyv = mk_p1_dyv(mds,row);
    dyv *cat_other_dyv = mk_other_dyv(mds,row);

    if ( dyv_size(cat_p1_dyv) < 3 )
      printf("Cat %d has too little p1 data\n",my_irint(ds_real_ref(mds,row,0)));
    else if ( dyv_size(cat_other_dyv) < 3 )
      printf("Cat %d has too little other data\n",my_irint(ds_real_ref(mds,row,0)));
    else
    {
      printf("Adding Cat %d\n",my_irint(ds_real_ref(mds,row,0)));
      for ( attnum = 1 ; attnum < ds_num_atts(mds) ; attnum++ )
        fprint_biggy_row(s,pds,mds,row,attnum);
    }

    free_dyv(cat_p1_dyv);
    free_dyv(cat_other_dyv);
  }
}

void explode_main(int argc,char *argv[])
{
  datset *D = mk_empty_datset();
  int i,j;
  const int nrows = 10;
  const int nsymbs = 4;
  /* names for symbolic attribute values */
  string_array *nms = mk_string_array(nsymbs);
  string_array_set(nms, 0, "eni");
  string_array_set(nms, 1, "meni");
  string_array_set(nms, 2, "mini");
  string_array_set(nms, 3, "moe");
  ds_add_symbolic_attribute(D, "symb", nms);
  ds_add_rows(D, nrows);

  /* populate datset */
  for(i=0; i<nrows; i++) {
    ds_symbol_set(D, i, 0, int_random(nsymbs));
  }

  /* explode */
  ds_symbolic_binary_explosion(D, 0);

  /* print */
  for(j=0; j<1+nsymbs; j++) {
    printf("%s ", ds_attnum_to_name(D, j));
  }
  printf("\n");
  for(i=0; i<nrows; i++) {
    for(j=0; j<1+nsymbs; j++) {
      printf("%d ", ds_symbol_ref(D, i, j));
    }
    printf("\n");
  }

  free_datset(D);
  free_string_array(nms);

}

void biggy_main(int argc,char *argv[])
{
  char *pds_fname = "\\users\\awm\\mars\\musson\\catkey.ds";
  char *mds_fname = "\\users\\awm\\mars\\musson\\matrix.txt";
  datset *pds = ds_load(pds_fname);
  datset *mds = ds_load(mds_fname);
  char *out_fname = "\\users\\awm\\mars\\musson\\combo.ds";
  FILE *s = safe_fopen(out_fname,"w");
  fprint_biggy(s,pds,mds);
  fclose(s);
  printf("Finished\n");
  free_datset(mds);
  free_datset(pds);
}


void prunedat_main(int argc,char *argv[])
{
  int num_irrelevant = int_from_args("num_irrelevant",argc,argv,10);
  int num_points = int_from_args("num_points",argc,argv,100);
  double noise = double_from_args("noise",argc,argv,0.333333333);
  char *filename = string_from_args("out",argc,argv,"irrel.ds");
  int i,k;
  FILE *s = safe_fopen(filename,"w");

  fprintf(s,"# This datafile generated by dsetmain/main.c\n"
            "# P(B|A) = %g, P(B|~A) = %g, P(A) = 0.5\n"
            "# so that B is a noisy copy of A and all other\n"
            "# attributes are irrelevant. Number of datapoints = %d\n",
            1.0-noise,noise,num_points);

  for ( i = 0 ; i < num_irrelevant ; i++ )
  {
    fprintf(s,"i%02d, ",i+1);
    if ( i == num_irrelevant/2 )
      fprintf(s,"  A, ");
  }
  fprintf(s,"  B\n");

  for ( k = 0 ; k < num_points ; k++ )
  {
    bool a_value = range_random(0.0,1.0) < 0.5;
    bool b_value_agrees = range_random(0.0,1.0) > noise;
    bool b_value = (b_value_agrees) ? a_value : !a_value;
    int i;
    for ( i = 0 ; i < num_irrelevant ; i++ )
    {
      fprintf(s,"%3s, ",(range_random(0.0,1.0)<0.5) ? "yes" : "no");
      if ( i == num_irrelevant/2 )
        fprintf(s,"%3s, ",(a_value) ? "yes" : "no");
    }
    fprintf(s,"%3s\n",(b_value) ? "yes" : "no");
  }

  fclose(s);

  printf("Saved %d datapoints in %s\n",num_points,filename);
}

int main(int argc,char *argv[])
{
  char *s = (argc > 1) ? argv[1] : "help";

  /*  memory_leak_check_args(argc,argv); */

  printf("Run: %s edit/biggy/prunedat in <datafilename>\n",argv[0]);

  if ( eq_string(s,"edit") )
  {
    void edit_main(int argc,char *argv[]);
    edit_main(argc,argv);
  }
  else if ( eq_string(s,"biggy") )
  {
    void biggy_main(int argc,char *argv[]);
    biggy_main(argc,argv);
  }
  else if ( eq_string(s,"d2s") )
  {
    void d2s_main(int argc,char *argv[]);
    d2s_main(argc,argv);
  }
  else if ( eq_string(s,"compat") )
  {
    void compat_main(int argc,char *argv[]);
    compat_main(argc,argv);
  }
  else if ( eq_string(s,"prunedat") )
  {
    void prunedat_main(int argc,char *argv[]);
    prunedat_main(argc,argv);
  }
  else if ( eq_string(s,"explode") )
  {
    void explode_main(int argc,char *argv[]);
    explode_main(argc,argv);
  }
  else if ( eq_string(s,"agony") )
    { 
    void test_mdfda(void);
    test_mdfda();
    }
  else
    printf("See main.c for help\n");

  wait_for_key();
  am_malloc_report();
  wait_for_key();
  return 0;
}

void test_mdfda(void)
{
  double foo[] = {2.5, 9.7, 11.8, 31.6, 3.14, 99.1, 65.44, 4.0};
  datset* moocow;

  moocow = mk_datset_from_double_arr(foo, 4,2);
  fprintf_datset(stdout, "", moocow, "\n");
  free_datset(moocow);
}

