//
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Tue Mar  8 17:05:00 PST 2011
// Last Modified: Sun Mar 27 13:36:19 PDT 2011 added label hyperlinks
// Last Modified: Sun Mar 27 17:34:54 PDT 2011 added ref record tooltips
// Filename:      ...sig/examples/all/humtable.cpp
// Web Address:   http://sig.sapp.org/examples/museinfo/humdrum/humtable.cpp
// Syntax:        C++; museinfo
//
// Description:   Print Humdrum file as an HTML table.
//

#include "humdrum.h"
#include "PerlRegularExpression.h"

#include <stdlib.h>
#include <string.h>

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


#define C0C0 "cellpadding=0 cellspacing=0"
#define TDSEP 10
#define TOKENWIDTH 70

// function declarations
void    checkOptions(Options& opts, int argc, char* argv[]);
void    example(void);
void    usage(const char* command);
void    createTable(ostream& out, HumdrumFile& infile);
void    printGlobalComment(ostream& out, HumdrumFile& infile, int line);
void    printReferenceRecord(ostream& out, HumdrumFile& infile, int line);
void    printFields(ostream& out, HumdrumFile& infile, int line);
int     getSubTracks(HumdrumFile& infile, int line, int track);
void    addLabelHyperlinks(Array<char>& strang);
void    addLabelHyperlinkName(Array<char>& strang);


// global variables
Options      options;            // database for command-line arguments
int          fullQ = 1;          // used with --page option
int          textareaQ = 0;      // used with --textarea option


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


int main(int argc, char* argv[]) {
   HumdrumFile infile, outfile;

   // process the command-line options
   checkOptions(options, argc, argv);

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

   if (fullQ) {
      cout << "<html><head><title>full page</title>\n";
      cout << "<style type=\"text/css\">\n";
      cout << "<!-- \n";
      cout << "a {text-decoration:none}\n";
      cout << ".hi:hover {background:#d0d0ff}\n";
      cout << "//-->\n";
      cout << "</style>\n";
      cout << "</head><body>\n";
   }

   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));
      }

      // analyze the input file according to command-line options
      createTable(cout, infile);
       
   }

   if (fullQ) {
      cout << "</body></html>\n";
   }

   return 0;
}


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

//////////////////////////////
//
// createTable --
//

void createTable(ostream& out, HumdrumFile& infile) {

   out << "<table " << C0C0 << ">\n";

   int i;
   for (i=0; i<infile.getNumLines(); i++) {
      if (infile[i].isGlobalComment()) {
         printGlobalComment(out, infile, i);
         continue;
      }
      if (infile[i].isBibliographic()) {
         printReferenceRecord(out, infile, i);
         continue;
      }
      if (infile[i].isData()) {
         printFields(out, infile, i);
      }
      if (infile[i].isMeasure()) {
         printFields(out, infile, i);
      }
      if (infile[i].isInterpretation()) {
         printFields(out, infile, i);
      }
   }

   out << "</table>\n";

   if (textareaQ) {
      out << "<textarea wrap=off rows=10 cols=70>";
      out << infile;
      out << "</textarea>\n";
   }

}



//////////////////////////////
//
// getSubTracks --
//

int getSubTracks(HumdrumFile& infile, int line, int track) {
   int& i = line;
   int j;
   int output = 0;
   for (j=0; j<infile[i].getFieldCount(); j++) {
      if (infile[i].getPrimaryTrack(j) == track) {
         output++;
      }
   }

   return output;
}



//////////////////////////////
//
// printFields --
//

void printFields(ostream& out, HumdrumFile& infile, int line) {
   out << "<tr class=\"hi\" valign=baseline>";
   int& i = line;
   int j;
   int track;
   int counter;
   int subtracks;
   PerlRegularExpression pre;
   Array<char> strang;

   for (track=1; track<=infile.getMaxTracks(); track++) {
      subtracks = getSubTracks(infile, line, track);
      out << "<td>";
      if (subtracks > 1) {
         out << "<table " << C0C0 << "><tr valign=top";
         if (infile[i].isMeasure()) {
            out << " bgcolor=#eeeeee ";
         }
         out << ">";
         counter = 0;
         for (j=0; j<infile[i].getFieldCount(); j++) {
            if (infile[i].getPrimaryTrack(j) == track) {
               strang.setSize(strlen(infile[i][j])+1);
               strcpy(strang.getBase(), infile[i][j]); 
               pre.sar(strang, " ", " ", "g");
               if (pre.search(strang, "^\\*>.*\\[", "")) {
                  addLabelHyperlinks(strang);
               } else if (pre.search(strang, "^\\*>", "")) {
                  addLabelHyperlinkName(strang);
               }
               out << "<td width=" << TOKENWIDTH << ">" << strang << "</td>";
               counter++;
               if (counter < subtracks) {
                  out << "<td width=" << TDSEP << "></td>";
               }
            }
         }
         out << "</tr></table>\n";
      } else {
         for (j=0; j<infile[i].getFieldCount(); j++) {
            if (infile[i].getPrimaryTrack(j) == track) {
               strang.setSize(strlen(infile[i][j])+1);
               strcpy(strang.getBase(), infile[i][j]); 
               pre.sar(strang, " ", " ", "g");
               if (pre.search(strang, "^\\*>.*\\[", "")) {
                  addLabelHyperlinks(strang);
               } else if (pre.search(strang, "^\\*>", "")) {
                  addLabelHyperlinkName(strang);
               }
               out << strang;
            }
         }
      }
      out << "</td>";
   }
   out << "</tr>\n";
}



//////////////////////////////
//
// addLabelHyperlinkName --
//

void addLabelHyperlinkName(Array& strang) {
   PerlRegularExpression pre;
   if (!pre.search(strang, "^\\*>([^\\[]+)$", "")) {
      return;
   }

   char buffer[1024] = {0};
   strcpy(buffer, "<a name=\"");
   strcat(buffer, pre.getSubmatch(1));
   strcat(buffer, "\"></a>");
   strcat(buffer, strang.getBase());
   strang.setSize(strlen(buffer)+1);
   strcpy(strang.getBase(), buffer);
}



//////////////////////////////
//
// addLabelHyperlinks --
//

void addLabelHyperlinks(Array& strang) {
   PerlRegularExpression pre;
   if (!pre.search(strang, "^\\*>(.*)\\[(.*)\\]", "")) {
      return;
   }

   char buffer[10123] = {0};
   strcpy(buffer, "*>");
   strcat(buffer, pre.getSubmatch(1));
   strcat(buffer, "[");

   PerlRegularExpression pre2;
   Array<Array<char> > tokens;
   pre2.getTokens(tokens, ",", pre.getSubmatch(2));
   
   int i;
   for (i=0; i<tokens.getSize(); i++) {
      strcat(buffer, "<a href=\"#");
      strcat(buffer, tokens[i].getBase());
      strcat(buffer, "\">");
      strcat(buffer, tokens[i].getBase());
      strcat(buffer, "</a>");
      if (i < tokens.getSize() - 1) {
         strcat(buffer, ",");
      }
   }
   strcat(buffer, "]");
   strang.setSize(strlen(buffer) + 1);
   strcpy(strang.getBase(), buffer);
}


//////////////////////////////
//
// printReferenceRecord --
//

void printReferenceRecord(ostream& out, HumdrumFile& infile, int line) {
   int& i = line;

   PerlRegularExpression pre;
   if (!pre.search(infile[line][0], "^!!!([^:]+):(.*)$", "")) {
      out << "<tr valign=baseline><td colspan=" << infile.getMaxTracks() << ">";
      out << "<font color=green>" << infile[i] << "</font></td></tr>";
      return;
   } 


   Array<char> description;
   char buffer[128] = {0};
   
   infile[line].getBibliographicMeaning(description, pre.getSubmatch(1));
   PerlRegularExpression pre2;
   pre2.sar(description, "\"", "", "g");

   out << "<tr valign=baseline><td colspan=" << infile.getMaxTracks() << ">";
   out << "<font color=green>";
   out << "<span title=\"";
   out << infile[line].getBibKey(buffer);
   out << ": ";
   out << description;
   out << "\">";

   out << "!!!";
   out << pre.getSubmatch(1);
   out << ":";
   out << pre.getSubmatch(2);

   out << "</span>";
   out << "</font></td></tr>";

}



//////////////////////////////
//
// printGlobalComment --
//

void printGlobalComment(ostream& out, HumdrumFile& infile, int line) {
   int& i = line;
   out << "<tr valign=baseline><td colspan=" << infile.getMaxTracks() << ">";
   out << "<font color=blue>" << infile[i] << "</font></td></tr>";
}



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

void checkOptions(Options& opts, int argc, char* argv[]) {
   opts.define("page|full|p=b", "print a full page instead of just table");
   opts.define("textarea|ta|t=b", "print data in a textarea after main table");

   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, March 2011" << endl;
      exit(0);
   } else if (opts.getBoolean("version")) {
      cout << argv[0] << ", version: March 2011" << 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);
   }


   fullQ     = opts.getBoolean("page");
   textareaQ = opts.getBoolean("textarea");


}



//////////////////////////////
//
// example -- example usage of the humtable program
//

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





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

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



// md5sum: e1c838725d9cdef3baa8f1da95da60ad humtable.cpp [20120727]