#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;

#include <boost/program_options.hpp>
namespace bpo = boost::program_options;

#include "legion.hpp"
#include "cudamaniple.hpp"
#include "cudatask.hpp"

// ==============================================================


class HelloTask : public SciGPU::Legion::CUDAtask {

public:

  HelloTask( void ) : CUDAtask() {} ;

  virtual bool Perform( void ) {
    
    this->maniple->LogMessage( "Hello from a thread!" );
    boost::posix_time::milliseconds slp(10);  
    boost::this_thread::sleep( slp );

    return( true );
  }

};

// ==============================================================

const unsigned int nManiplesDefault = 2;
const unsigned int nHellosDefault = 20;

unsigned int nManiples;
unsigned int nHellos;


void ReadCommandLine( int ac, char* av[] ) {

  try {
    bpo::options_description generic("Generic options");
    generic.add_options()
      ("help", "Produce help message" )
      ;

    bpo::options_description control("Control options");
    control.add_options()
      ("maniples",bpo::value<unsigned int>(&nManiples)->default_value(nManiplesDefault),"Number of maniples to enlist")
      ("msgs",bpo::value<unsigned int>(&nHellos)->default_value(nHellosDefault),"Number of messages to output")
      ;

    bpo::options_description cmdLine;
    cmdLine.add(generic).add(control);

    bpo::variables_map vm;
    bpo::store( bpo::command_line_parser(ac, av).
		options(cmdLine).run(), vm );
    bpo::notify( vm );
    
    if( vm.count( "help" ) ) {
      cout << cmdLine << endl;
      exit( EXIT_SUCCESS );
    }
  }
  catch( exception& e ) {
    cerr << "Error: " << e.what() << endl;
    exit( EXIT_FAILURE );
  }
  catch( ... ) {
    cerr << "Unknown exception" << endl;
    exit( EXIT_FAILURE );
  }

}

  



// ==============================================================

int main( int argc, char *argv[] ) {

  ReadCommandLine( argc, argv );

  cout << "Legion CUDA Hello" << endl;
  cout << "=================" << endl << endl;

  // Create the Legion
  SciGPU::Legion::Legion myLegion;

  // Give the Legion some Maniples
  for( unsigned int i=0; i<nManiples; i++ ) {
    SciGPU::Legion::CUDAmaniple myManiple;
    myManiple.gpuID = i;
    myLegion.AddManiple( myManiple );
  }

  
  // Declare the list of tasks
  HelloTask hello;
  vector<HelloTask> hellos(nHellos,hello);

  // Enqueue them
  for( unsigned int i=0; i<hellos.size(); i++ ) {
    myLegion.Enqueue( &(hellos.at(i)) );
  }

  // Wait for completion
  volatile size_t nComplete;
  do {
    nComplete = myLegion.CountComplete();
  } while( nComplete < hellos.size() );

  cout.flush();
  clog.flush();
  cerr.flush();
  cout << "Press ENTER to exit" << endl;
  cin.get();
  

  return( EXIT_SUCCESS );
}
