//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun Feb 20 17:26:38 PST 2011
// Last Modified: Sun Feb 20 17:26:44 PST 2011
// Filename:      ...sig/examples/all/prthumb.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/prthumb.cpp
// Syntax:        C++; museinfo
//
// Description: Create a match location summary from theloc output with 
//              percent output.
//

#include "humdrum.h"
#include "Matrix.h"
#include "PixelColor.h"
#include "SigString.h"
#include "PerlRegularExpression.h"

#ifndef OLDCPP
   #include <iostream>
   #include <fstream>
#else
   #include <iostream.h>
   #include <fstream.h>
#endif

#define GRAY 230

// function declarations
void      checkOptions(Options& opts, int argc, char* argv[]);
void      example(void);
void      usage(const char* command);
void      printImage(Matrix<PixelColor>& image);
void      processData(Array<SigString>& data);
void      readData(Array<SigString>& data, istream& input);
void      readData(Array<SigString>& data, const char* filename);
void      getStartStop(int& start, int& stop, Array<char>& field, 
                               int width);
void      addDataLine(Matrix<PixelColor>& image, SigString& astring,
                               int width, int offset, int row);


// global variables
Options      options;            // database for command-line arguments


///////////////////////////////////////////////////////////////////////////


int main(int argc, char* argv[]) {
   // process the command-line options
   checkOptions(options, argc, argv);
   Array<SigString> data;

   // figure out the number of input files to process
   int numinputs = options.getArgCount();

   for (int i=0; i<numinputs || i==0; i++) {

      // if no command-line arguments read data file from standard input
      if (numinputs < 1) {
         readData(data, cin);
      } else {
         readData(data, options.getArg(i+1));
      }

      // analyze the input file according to command-line options
      processData(data);

   }

   return 0;
}


///////////////////////////////////////////////////////////////////////////


//////////////////////////////
//
// readData --
//

void readData(Array& data, istream& infile) {
   data.setSize(100);
   data.setSize(0);
   data.setGrowth(1123123);
   char buffer[10123];
   int counter = 0;

   while (!infile.eof()) {
      infile.getline(buffer, 4096, '\n');
      // this line causes an infinite loop occasionally:
      //if (infile.eof() && (strcmp(buffer, "") == 0)) {
      if (infile.eof()) {
         break;
      } else if (strcmp(buffer, "") == 0) {
         counter++;
         if (counter > 10) {
            break;
         }
      } else {
         data.increase();
         data.last() = buffer;
      }
   }
}


void readData(Array& data, const char* filename) {
   ifstream infile(filename, ios::in);
   if (!infile.is_open()) {
      cerr << "ERROR cannot open file: " << filename << " for reading" << endl;
      exit(1);
   }
   readData(data, infile);
}



//////////////////////////////
//
// processData --
//

void processData(Array& data) {
   PerlRegularExpression pre;

   int cols = 50;
   int rows = data.getSize() + 2;
   int offset = 1;

   // PixelColor  background(255, 255, 255);
   PixelColor  background(GRAY, GRAY, GRAY);
   Matrix<PixelColor> image(rows, cols, background);

   // draw border around image
   PixelColor border(GRAY,GRAY,GRAY);
   int i;
   int j;
   for (i=0; i<rows; i++) {
      image.cell(i, 0) = border;
      image.cell(i, cols-1) = border;
   }
   for (j=1; j<cols-1; j++) {
      image.cell(0, j) = border;
      image.cell(rows-1, j) = border;
   }

   for (i=0; i<data.getSize(); i++) {
      addDataLine(image, data[i], cols-2, offset, i+offset);
   }

   printImage(image);
}



//////////////////////////////
//
// addDataLine -- Add a line of data to the image.
//

void addDataLine(Matrix<PixelColor>& image, SigString& astring, int width,
      int offset, int row) {
   PixelColor black      (0,   0,     0);
   PixelColor red        (255, 0,     0);
   PixelColor orange     (255, 100,   0);
   PixelColor green      (0,   244,   0);
   PixelColor blue       (90,   90, 255);
   PixelColor purple     (200,   0, 200);
   PixelColor yellowgreen(150, 200,   0);

   PixelColor* pixel = &black;
   Array<Array<char> > tokens;
   tokens.setSize(10000);
   tokens.setGrowth(1000000);
   tokens.setSize(0);
   PerlRegularExpression pre;
   PerlRegularExpression pre2;
   pre.getTokens(tokens, "\\s+", astring.getBase());
   int i, j;
   int start, stop;
   pre.search(tokens[0], ":(.*):", "");
   if (pre.search(pre.getSubmatch(1), "Bassus", "i")) {
      pixel = &red;
   } else if (pre.search(pre.getSubmatch(), "Contra", "i")) {
      pixel = &orange;
   } else if (pre.search(pre.getSubmatch(), "Tenor", "i")) {
      pixel = &blue;
   } else if (pre.search(pre.getSubmatch(), "Altus", "i")) {
      pixel = &purple;
   } else if (pre.search(pre.getSubmatch(), "Superius", "i")) {
      pixel = &green;
   } else if (pre.search(pre.getSubmatch(), "Discantus", "i")) {
      pixel = &yellowgreen;
   }

   for (i=1; i<tokens.getSize(); i++) {
      getStartStop(start, stop,  tokens[i], width);
      if (start < 0) {
         continue;
      }
      for (j=start; j<=stop; j++) {
         image.cell(row, j+offset) = *pixel;
      }
   }
}



//////////////////////////////
//
// getStartStop -- return the location of the match in the file
//

void getStartStop(int& start, int& stop, Array& field, int width) {
   double start1, stop1;
   PerlRegularExpression pre;
   if (pre.search(field, "P(\\d+).*-.*P(\\d+)", "")) {
      start1 = atoi(pre.getSubmatch(1));
      stop1  = atoi(pre.getSubmatch(1));
      start  = int(start1 / 100.0 * width);
      stop   = int(stop1 / 100.0 * width);
   } else if (pre.search(field, "P(\\d+)", "")) {
      start1 = atoi(pre.getSubmatch(1));
      start  = int(start1 / 100.0 * width);
      stop = start;
   } else {
      start = -1;
      stop = -1;
   }
}



//////////////////////////////
//
// printImage -- PNM image
//

void printImage(Matrix& image) {
   int rows = image.getRowCount();
   int cols = image.getColumnCount();
 
   cout << "P3\n";                       // indicates text-based  PPM image
   cout << cols*2 << ' ' << rows*2 << '\n';  // size of image
   cout << "255\n";                      // number of color levels per pixel
   int i, j;
   for (i=rows-1; i>=0; i--) {
      for (j=0; j<cols; j++) {
         cout << image.cell(i,j) << ' ';
         cout << image.cell(i,j) << ' ';
      }
      for (j=0; j<cols; j++) {
         cout << image.cell(i,j) << ' ';
         cout << image.cell(i,j) << ' ';
      }
      cout << '\n';
   }
}


//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//

void checkOptions(Options& opts, int argc, char* argv[]) {

   opts.define("d|debug=b");                    // determine bad input line num
   opts.define("author=b");                     // author of program
   opts.define("version=b");                    // compilation info
   opts.define("example=b");                    // example usages
   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, May 1998" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: Nov 2000" << 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);
   }


}



//////////////////////////////
//
// example -- example usage of the sonority program
//

void example(void) {
   cout <<
   "                                                                         \n"
   << endl;
}



//////////////////////////////
//
// usage -- gives the usage statement for the sonority program
//

void usage(const char* command) {
   cout <<
   "                                                                         \n"
   << endl;
}



// md5sum: 5af703745cdb78d39317dd01554631f9 prthumb.cpp [20120404]