struct ListItemStruct
{
  float mVal;
  int mPos;
};
typedef struct ListItemStruct ListItem;


void printDiscrData()
{
  int c, att, attVal, item;
  char *fName = (char*)malloc( sizeof(char) ), *nameStr, *dataStr, *tmp;
  FILE *names, *data;
  fName[0] = '\0';
  tmp = strtok( FileName, "/" );
  while ( tmp != NULL )
  {
    free( fName );
    fName = (char*)malloc( sizeof( char ) * strlen(tmp) );
    strcpy( fName, tmp );
    tmp = strtok( NULL, "/" );
  }
  nameStr = (char*)malloc( sizeof( char ) * ( strlen(fName) + 15 ) );
  dataStr = (char*)malloc( sizeof( char ) * ( strlen(fName) + 15 ) );
  sprintf( nameStr, "%sDiscr.names", fName );
  sprintf( dataStr, "%sDiscr.data", fName );

  
  names = fopen( nameStr, "w" );
  // Print the classes
  fprintf( names, "%s", ClassName[0] );
  for ( c = 1; c < MaxClass+1; c++ ) fprintf( names, ",%s", ClassName[c] );

  // Print all the attributes
  for ( att = 0; att < MaxAtt+1; att++ )
  {
    fprintf( names, "\n%s: %s", AttName[att], AttValName[att][1] );
    for ( attVal = 2; attVal < MaxAttVal[att]+1; attVal++ )
      fprintf( names, ",%s", AttValName[att][attVal] );
  }
  fprintf( names, "\n" );
  fclose( names );

  data = fopen( dataStr, "w" );
  for ( item = 0; item < MaxItem; item++ )
  {
    if ( Item[item][0]._discr_val == 0 ) fprintf( data, "?" );
    else fprintf( data, "%s", AttValName[0][Item[item][0]._discr_val] );
    for ( att = 1; att < MaxAtt+1; att++ )
      if ( Item[item][att]._discr_val == 0 ) fprintf( data, ",?" );
      else fprintf( data, ",%s", AttValName[att][Item[item][att]._discr_val] );
    fprintf( data, ",%s\n", ClassName[Class(Item[item])] );
  }
  fclose( data );
}



int compareListItems( const ListItem *i, const ListItem *j )
{
  float x = i->mVal, y = j->mVal;
  if ( x < y ) return -1;
  else if ( x > y ) return 1;
  return 0;
}

/*
 * This method will take in data in the format that Quinlan's C4.5 expects and discretize the real
 * number-valued attributes with equal frequency. That is, each bin will have the same number of
 * of values in it, it is the ranges that differ. The run time of this Algorithm is O( mnlg(n) ) where:
 * n is the number of data instances and m is the number of attributes that are real-valued.
 * @param bins The number of bins to discretize the data into.
 */
void eqFr( int bins, int isEff )
{
  // The indexes of the real number-valued attribtues.
  int att, item, attVal, b;
  
  // Go through each attribute, if it is real, we need to discretize it.
  for( att = 0; att < MaxAtt+1; att++ )
  {
    if ( SpecialStatus[att] == Nil )
    {
      // Create an array of all values of the current attribute so I can sort them with qsort.
      // I can then easily bin them.  The values are stored in a structure along with a key.
      // This key holds the true position in the original item list.  This allows me to
      // easily do a lookup. Running time of this is 2n. n is the number of instances.
      // Declare an array of mins and an array of maxes for the range decision.
      // This is used in the naming of the value.
      float *maxes = (float*)malloc( sizeof( float ) * bins ),
	    *mins  = (float*)malloc( sizeof( float ) * bins );
      int *counts = (int*)malloc( sizeof( int ) * bins );
      for ( b = 0; b < bins; b++ )
      {
	counts[b] = 0;
	maxes[b] = -999999;
	mins[b] = 999999;
      }

      ListItem *attList = (ListItem*)malloc( sizeof( ListItem ) * MaxItem );
      for ( item = 0; item < MaxItem; item++ )
      {
	attList[item].mVal = Item[item][att]._cont_val;
	attList[item].mPos = item;
      }

      qsort( attList, MaxItem, sizeof( ListItem ), compareListItems );
      
      // Replace each continuous value with a discrete value( The index of the bin in the names list )
      for ( item = 0; item < MaxItem; item++ )
      {
	int binNo, pos = attList[item].mPos;
	binNo = item/(float)MaxItem * bins + 1;
	mins[binNo-1] = mins[binNo-1] > Item[pos][att]._cont_val ? Item[pos][att]._cont_val : mins[binNo-1];
	maxes[binNo-1] = maxes[binNo-1] < Item[pos][att]._cont_val ? Item[pos][att]._cont_val : maxes[binNo-1];
	Item[pos][att]._discr_val = binNo;
      }

      // Do some bookeeping stuff, make the attribute discrete and set its max value to the number of bins.
      //SpecialStatus[att] = DISCRETE;
      MaxAttVal[att] = bins;

      // Now that we have the mins and maxes for each bin, set each AttValName[att][attVal] to be
      // [ min to max ]
      AttValName[att] = (char**)realloc( AttValName[att], (bins+1) * sizeof( char* ) );
      for ( attVal = 1; attVal < bins+1; attVal++ )
      {
	AttValName[att][attVal]  = (char *)malloc( sizeof( char ) * 50 );
	if ( isEff ) sprintf( AttValName[att][attVal], "[ %4.2f to %4.2f ]\0", exp( mins[attVal-1] ), exp( maxes[attVal-1] ) );
	else sprintf( AttValName[att][attVal], "[ %4.2f to %4.2f ]\0", mins[attVal-1], maxes[attVal-1] );
	//AttValName[att][attVal] = (char *)malloc( sizeof( char ) * 5 );
	//sprintf( AttValName[att][attVal], "_%2d_\0", attVal );
      }

      // Cleanup
      free( mins );
      free( maxes );
      free( attList );
    }
  }
}
