//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Mar 24 16:40:42 PST 2005
// Last Modified: Thu Mar 24 16:40:44 PST 2005
// Filename:      ...sig/examples/all/irangeplot.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/irangeplot.cpp
// Syntax:        C++; museinfo
//
// Description:   Plot data generated by the irange program.
// 
#include "humdrum.h"
#define MAX_CODES 3
// function declarations
void   checkOptions(Options& opts, int argc, char* argv[]);
void   example(void);
void   usage(const char* command);
void   storeData(HumdrumRecord& aRecord, int index, 
                                 Array<Array<int> >& rdata);
void   printData(HumdrumFile& infile, 
                                 Array<Array<int> >& rdata);
void   generateAnalysis(HumdrumFile& infile, 
                                 Array<Array<int> >& rdata);
void   analyzeLevel(Array<Array<double> >& codecount, 
                                 Array<Array<int> >& rdata, int level);
void   printRow(Array<Array<double> >& codecount);
void   plotData(Array<Array<int> >& rdata);
// global variables
Options      options;            // database for command-line arguments
int          debugQ     = 0;     // used with the --debug option
int          activityQ  = 0;     // used with the -a option
int          localQ     = 0;     // used with the -l option
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
   HumdrumFile infile;
   // process the command-line options
   checkOptions(options, argc, argv);
   // figure out the number of input files to process
   int numinputs = options.getArgCount();
   Array<double> values;
   values.setSize(0);
   Array<Array<int> > rdata;
   for (int i=0; i<numinputs || i==0; i++) {
      infile.clear();
      // if no command-line arguments read data file from standard input
      if (numinputs < 1) {
         infile.read(cin);
      } else {
         infile.read(options.getArg(i+1));
      }
      generateAnalysis(infile, rdata);
      if (debugQ) {
         printData(infile, rdata);
      }
      plotData(rdata);
   }
   return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// plotData --
//
void plotData(Array >& rdata) {
   // print header
   cout  << "P3\n";
   int rows = rdata.getSize();
   int cols = rdata.getSize();
   cout  << rows << " " << cols << "\n";
   cout  << "255\n";
   Array<Array<double> > codecount(MAX_CODES);
   int i;
   for (i=0; i<codecount.getSize(); i++) {
      codecount[i].setSize(cols);
   }
   for (i=rows-1; i>=0; i--) {
      analyzeLevel(codecount, rdata, i);
      printRow(codecount);
   }
}
//////////////////////////////
//
// printRow -- 
//
void printRow(Array >& codecount) {
   int i;
   int j;
   for (i=0; i<codecount[0].getSize(); i++) {
      for (j=0; j<3; j++) {
         cout << (int)(256 * codecount[j][i]) << " ";
      }
   }
   cout << "\n";
}
//////////////////////////////
//
// analyzeLevel -- 
//
void analyzeLevel(Array<Array<double> >& codecount, Array<Array<int> >& rdata, 
      int level) {
   int i;
   int j;
   int k;
   for (i=0; i<codecount.getSize(); i++) {
      codecount[i].zero();
   }
   for (i=0; i<rdata.getSize(); i++) {
      if (i+level >= rdata.getSize()) {
         break;
      }
      for (j=0; j < level + 1; j++) {
         for (k=0; k<rdata[i+j].getSize(); k++) {
            if ((rdata[i+j][k] >= 0) && (rdata[i+j][k] < MAX_CODES)) {
               codecount [rdata[i+j][k]] [i] += 1.0;
            }
         }
      } 
   }
   
   Array<double> max(rdata.getSize());
   max.setAll(0.0);
   double globalmax = 0.0;
   Array<double> colormax(3);
   colormax.setAll(0.0);
   for (i=0; i<codecount.getSize(); i++) {  // small dimension
      for (j=0; j<rdata.getSize(); j++) {   // big dimension
         if (codecount[i][j] > colormax[i]) {
            colormax[i] = codecount[i][j];
         }
         if (codecount[i][j] > max[j]) {
            max[j] = codecount[i][j];
         }
         if (codecount[i][j] > globalmax) {
            globalmax = codecount[i][j];
         }
      }
   }
   if (globalmax <= 0.0) {
      return;
   }
   
   if (activityQ) {
      // nomalize one row of pixels according to the maximum
      // count of all range values on a level.
      // normalize the codecount data
      for (i=0; i<codecount.getSize(); i++) {
         for (j=0; j<codecount[0].getSize(); j++) {
            codecount[i][j] /= globalmax;
         }
      }
   } else if (localQ) {
      // normalize each pixel on a level according to the maximum 
      // count for that pixel (local normalization)
      for (i=0; i<codecount.getSize(); i++) {   // small
         for (j=0; j<codecount[i].getSize(); j++) {  // big
            if (max[j] > 0.0) {
               codecount[i][j] /= max[j];
            }
         }
      } 
   } else {
      for (i=0; i<codecount.getSize(); i++) {   // small
         for (j=0; j<codecount[i].getSize(); j++) {  // big
            if (colormax[i] > 0.0) {
               codecount[i][j] /= colormax[i];
            }
         }
      }
   }
}
//////////////////////////////
//
// printData --
//
void printData(HumdrumFile& infile, Array >& rdata) {
   int i;
   int j;
   for (i=0; i<rdata.getSize(); i++) {
      for (j=0; j<rdata[i].getSize(); j++) {
         cout << rdata[i][j];
         if (j < rdata[i].getSize() - 1) {
            cout << " ";
         }
      }
      cout << "\n";
   }
}
/*
int main(void) {
   int i = 1;
   increment(&i)
   print("i=%d\n", i);
   // i=2
}
void increment(int *i) {
   *i = *i + 1;
}
int main(void) {
   int i = 1;
   increment(i)
   print("i=%d\n", i);
   // i=2
}
void increment(int &i) {
   i = i + 1;
}
*/
/*
class ACLass {
   public:
      void setData(int adata);
   private:
      int data1;
};
void AClass::setData(int adata) {
    this->data1 = adata;
}
template<class foo>
class ACLass<foo> {
   public:
      void setData(int adata);
   private:
      int data1;
};
template<class foo>
void AClass<foo>::setData(int adata) {
    this->data1 = adata;
}
AClass<int>
*/
//////////////////////////////
//
// generateAnalysis -- Extract the H, M, L tokens from all **irange spines.
//
void generateAnalysis(HumdrumFile& infile, Array >& rdata) {
   rdata.setSize(infile.getNumLines());
   rdata.setSize(0);
   int i;
   int j;
   for (i=0; i < infile.getNumLines(); i++) {
      if (infile[i].getType() != E_humrec_data) {
         continue;
      }
      for (j=0; j < infile[i].getFieldCount(); j++) {
         if (strcmp(infile[i].getExInterp(j), "**irange") == 0) {
            storeData(infile[i], j, rdata);
         }
         break;
      }
   }
}
//////////////////////////////
//
// storeData --
//
#define TIM_UNKNOWN -1
#define TIM_LOW  0
#define TIM_MID  1
#define TIM_HIGH 2
void storeData(HumdrumRecord& aRecord, int index, Array >& rdata) {
   rdata.setSize(rdata.getSize()+1);
   rdata[rdata.getSize()-1].setSize(32);
   rdata[rdata.getSize()-1].setSize(0);
   int i;
   char buffer[1024] = {0};
   int item = 0;
   int tokencount = aRecord.getTokenCount(index);
   for (i=0; i<tokencount; i++) {
      aRecord.getToken(buffer, index, i);
      switch (buffer[0]) {
         case 'L': item = TIM_LOW;  break;
         case 'M': item = TIM_MID;  break;
         case 'H': item = TIM_HIGH; break;
         default:  item = TIM_UNKNOWN;
      }
      if (item != TIM_UNKNOWN) {
         rdata[rdata.getSize()-1].append(item);
      }
   }
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
   opts.define("a|activity=b",  "do activity normalization");   
   opts.define("l|local=b",     "do local normalization");   
   opts.define("debug=b",       "trace input parsing");   
   opts.define("author=b",      "author of the program");   
   opts.define("version=b",     "compilation information"); 
   opts.define("example=b",     "example usage"); 
   opts.define("h|help=b",      "short description"); 
   opts.process(argc, argv);
   
   // handle basic options:
   if (opts.getBoolean("author")) {
      cout << "Written by Craig Stuart Sapp, "
           << "craig@ccrma.stanford.edu, Mar 2005" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: 24 Mar 2005" << endl;
      cout << "compiled: " << __DATE__ << endl;
      cout << MUSEINFO_VERSION << endl;
      exit(0);
   } else if (opts.getBoolean("help")) {
      usage(opts.getCommand());
      exit(0);
   } else if (opts.getBoolean("example")) {
      example();
      exit(0);
   }
   debugQ    = opts.getBoolean("debug");
   activityQ = opts.getBoolean("activity");
   localQ    = opts.getBoolean("local");
}
//////////////////////////////
//
// example -- example usage of the maxent program
//
void example(void) {
   cout <<
   "                                                                        \n"
   << endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the quality program
//
void usage(const char* command) {
   cout <<
   "                                                                        \n"
   << endl;
}
// md5sum: e0a551b9efec67c31ae88846c6d06ecc irangeplot.cpp [20080227]