/*
file: chord.cpp
author: Nate Sommer

Given an input file that lists probabilities, this program generates a chord 
progression.

*/

#include<string>
#include<vector>
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<ctime>

using namespace std;

// attributes class
// some variables to keep track of where we are in the chord progression, plus
// the probability table
class attributes {
public:
  attributes( vector< vector <int> > table ) {
    prob = table;
    next = 1;
    last = 0;
    curpos = 0;
    lastpos = prob.size() / 7;
  }

  int next;     // next chord
  int lastpos;  // last chord position in the progression, used for stopping
  int last;     // last chord
  int curpos;   // current chord position in the progression
  vector< vector <int> > prob; // probability table
};

// vector< vector <int> > build_table( string filename )
// takes a file specified on the command line and builds a 2-d array
vector< vector <int> > build_table( string filename );

// void print_vector( vector< vector <int> > & prob )
// prints the table to stdout
void print_vector( vector< vector <int> > & prob );

// void generate()
// generates a chord progression based on prob and writes an ABC file
void generate( vector< vector <int> > & prob, attributes attr, 
               string abcfilename );

// void make_midi()
// writes a midi file using abc2midi
void make_midi( string abcfilename );

int main( size_t argc, char** argv ) {
  if( argc < 2 ) {
    cout << "Usage: " << argv[0] << " <filename>" << endl;
    return -1;
  }
  string abcfile;
  if( argc == 3 ) {
    abcfile = argv[2];
  }
  else {
    abcfile = "out.abc";
  }
  string filename( argv[1] );
  vector< vector <int> > prob = build_table( filename );
  srand( time( NULL ) );

  attributes attr( prob );
  generate( prob, attr, abcfile );
  make_midi( abcfile );

  return 0;
}

vector< vector <int> > build_table( string filename ) {
  int num;
  ifstream instream;
  instream.open( filename.c_str() );
  instream >> num;
  vector< vector <int> > prob( (num - 1) * 7, 7 );
  for( int i = 0; instream; ++i ) {
    instream >> prob[i][0] >> prob[i][1] >> prob[i][2] 
             >> prob[i][3] >> prob[i][4] >> prob[i][5] 
             >> prob[i][6];
  }

  return prob;
}

void print_vector( vector< vector <int> > & prob ) {
  for( int i = 0; i < prob.size(); ++i ) {
    for( int j = 0; j < 7; ++j ) {
      cout << prob[i][j] << " ";
    }
    cout << endl;
  }
}


void generate( vector< vector <int> > & prob, attributes attr, 
               string abcfilename ) {
  ofstream abcfile;
  abcfile.open( abcfilename.c_str() );
  abcfile << "X: 1\nL:1/2\nM:4/4\nQ:1/4=110\nK:C\n";

  int row, r, num;
  while( attr.curpos < attr.lastpos ) {

    if( attr.next == 1 ) {
      cout << "I ";
      abcfile << "[CEG] ";
    }
    if( attr.next == 2 ) {
      cout << "ii ";
      abcfile << "[DFA] ";
    }
    if( attr.next == 3 ) {
      cout << "iii ";
      abcfile << "[EGB] ";
    }
    if( attr.next == 4 ) {
      cout << "IV ";
      abcfile << "[FAC] ";
    }
    if( attr.next == 5 ) {
      cout << "V ";
      abcfile << "[GBd] ";
    }
    if( attr.next == 6 ) {
      cout << "vi ";
      abcfile << "[Ace] ";
    }
    if( attr.next == 7 ) {
      cout << "vii ";
      abcfile << "[Bdf] ";
    }
    if( (attr.curpos + 1) % 2 == 0 ) {
      abcfile << "| ";
    }
    // figure out which row we're interested in
    row = attr.curpos * 7 + (attr.next - 1);
    attr.curpos++;
    attr.last = attr.next;
    r = (int)( 100 * ( (float)rand() / (float)RAND_MAX ) );
    num = 0;

    // calculate the next chord
    for( int i = 0; i < 7; ++i ) {
      num += attr.prob[row][i];
      if( r <= num ) {
        attr.next = i + 1;
        break;
      }
    }
  }
  cout << endl;
  abcfile << endl;
}

void make_midi( string abcfilename ) {
  string command = "abc2midi ";
  command += abcfilename;
  system( command.c_str() );
}

