/***************************************************************************
                          calc.cpp  -  description
                             -------------------
    begin                : Mon Apr 15 2002
    copyright            : (C) 2002 by Ross Andrews
    email                : randrews@geekfu.org
 ***************************************************************************/

//#define ONEROW // Only do one row, then exit
#define CALC // Calculate the row/rows
#define STORE // Store rows to the database

//#define THREADBUG // Some debug output for a single combination running bug.

#include "resultset.h"
#include <vector>
#include "rack.h"
#include "module.h"
#include "station.h"
#include "row.h"

#include <iostream>
#include <fstream>
#include <unistd.h>

#define HOST   "127.0.0.1"
#define USER   "root"
#define PASS   "blah"
#define DATA   "plum_data"
#define OUTPUT "plum_output"

using namespace std;

vector<rack> getracks(MYSQL);
vector<int> getstatus(MYSQL,int);
row makerow(row,vector<rack>,vector<int>,string,int);

int main(int argc,char** argv){
#ifdef THREADBUG
  ofstream fout;
  fout.open("/Users/randrews/Desktop/PLUM/bin/threadbug.log");
#endif

  ////////// Parse command line ///////////
  // Normal variables
  string host=HOST,name=USER,pass=PASS,data=DATA,output=OUTPUT; // DB connection data
  int run; // Which run we're doing
  MYSQL conn; // The DB connection object
  // Single combo variables
  string combo; // The combo for a single-combo run
  bool singlecombo=false; // Whether we're doing one combo
  int needssams=0; // Whether this single combination needs SAMS.

  if(argc!=2 && argc!=3 && argc!=4 && argc!=7 && argc!=8 && argc!=9) // Too few/many args, error.
    {
      cout<<"Usage: "<<argv[0]<<" <run> [<combo> [<needssams>]] [<host> <username> <pass> <datadb> <outputdb>]\n";
      exit(1);
    }
  
  run=atoi(argv[1]);
  switch(argc)
    {
    case 3:needssams=0;singlecombo=true;break;
    case 4:needssams=atoi(argv[3]);singlecombo=true;break;
    case 7:host=argv[2];name=argv[3];pass=argv[4];data=argv[5];output=argv[6];break;
    case 8:singlecombo=true;needssams=0;combo=argv[2];host=argv[3];name=argv[4];pass=argv[5];data=argv[6];output=argv[7];break;
    case 9:singlecombo=true;needssams=atoi(argv[3]);host=argv[4];name=argv[5];pass=argv[6];data=argv[7];output=argv[8];break;
    }
  if(singlecombo)combo=argv[2];

#ifdef THREADBUG
  fout<<"finished parsing command line\n";
#endif

  conn=ResultSet::makeConn(host,name,pass,data);

#ifdef THREADBUG
  fout<<"finished making connection to database\n";
#endif

  ////////// Get run data, make a blank row //////////
  ResultSet res(&conn);
  res.query<<"select idx from runs where idx="<<run;
  res.store();res.next();
  if(res.size()==0)
    {
      cout<<"Run "<<run<<" not found.\n";
      exit(1);
    }

#ifdef THREADBUG
  fout<<"Got run data and blank row\n";
#endif

  station stat(conn); // Build an empty station
  row blankrow(conn,run,data); // Build a row with all the data, but no racks.

#ifdef THREADBUG
  fout<<"Built empty station and template row\n";
#endif

  ////////// Get all the rack and status data from the database ///////////
  vector<rack> racks=getracks(conn);
  vector<int> status=getstatus(conn,run);

#ifdef THREADBUG
  fout<<"Retreived rack data\n";
#endif

  ////////// Update rack data based on SAMS //////////
  if(blankrow.run.newsams)
    {
      res.query<<"select racks.acronym as samsname from racks where sams=2";
      res.store();res.next();
      string samsname=(string)res["samsname"]; 
      for(int n=0;n!=racks.size();n++)
	if(racks[n].name == samsname)
	  { // The SAMS power doesn't count against that rack's power reqs, otherwise it would count twice.
	    racks[n].power-=blankrow.run.ku_power+blankrow.run.pl_power+blankrow.run.sams_power;
	    racks[n].keepalive_power-=blankrow.run.ku_power+blankrow.run.pl_power+blankrow.run.sams_power;
	    break;
	  }
    }

#ifdef THREADBUG
  fout<<"Retreived SAMS data\n";
#endif

  ////////// Are we doing one combo? //////////
  if(singlecombo)
    {
#ifdef THREADBUG
  fout<<"In single combo\n";
#endif

      // Turn combo into whatever makerow is expecting here
      row current=makerow(blankrow,racks,status,combo,needssams);

#ifdef THREADBUG
  fout<<"Made the single combo row\n";
#endif

      current.calc();

#ifdef THREADBUG
  fout<<"Calculated the results of the combination\n";
#endif

#ifdef THREADBUG
  current.dump(fout);
  cout<<"Finished with single combo!\n";
#else
  current.dump(cout);
  cout.flush();
#endif

#ifdef THREADBUG
  fout<<"Printed results to cout\n";
#endif

      // output something to stdout here
      return 0;
    }

  ////////// Get all the combos from the database ///////////
  ResultSet combos(&conn);
  combos.query<<"select idx,selects,needssams from "<<output<<"."<<blankrow.run.tblname;
  combos.store();

  ////////// Get status_idx ///////////
  // 	query<<"insert into "<<output<<".runstatus(progress) values (0)";
  // 	query.store();
  //  	query<<"select last_insert_id() as idx from "<<output<<".runstatus";
  //  	Result status_res=query.store();
  //  	int status_idx=(int)status_res[0]["idx"];
  //  	cout<<status_idx<<'\n'<<flush; // Not debug output, required for Java interface progress bar

  ////////// Calc and fork ///////////
  while(combos.next())
    {
      row current=makerow(blankrow,racks,status,(string)combos["selects"],(int)combos["needssams"]);
      current.calc();
      current.store((int)combos["idx"],output); // This should be forked.
    }
  return 0;
}

/////////////////////////////////
/// getracks
///
/// Makes a vector<rack> containing all the racks in the database
/////////////////////////////////
vector<rack> getracks(MYSQL conn){
  vector<rack> racks;
  ResultSet res(&conn);
  res.query<<"select acronym from racks order by idx asc";
  res.store();
  while(res.next())
    racks.push_back(rack(conn,(string)res["acronym"]));
  return racks;
}

/////////////////////////////////////////
/// getstatus
///
/// Gets all the rack status values from selection
/////////////////////////////////////////
vector<int> getstatus(MYSQL conn,int run){
  ResultSet res(&conn);
  res.query<<"select status from selection where run="<<run<<" order by rack asc";
  res.store();
  vector<int> status;
  while(res.next())
    status.push_back((int)res["status"]);
  return status;
}

////////////////////////////////////////////////////
/// makerow
///
/// Makes a vector<rack> containing all the racks in a given combo
////////////////////////////////////////////////////
row makerow(row empty,vector<rack> racks,vector<int> status,string combo,int needssams){
  vector<rack> c,k;
  for(int n=0;n!=combo.length();n++)
    {
      // For some reason, the combo strings are longer than the list of racks. So, to fix this....
      if(n==racks.size() || n==status.size())break;

      if(combo[n]=='1' || combo[n]==1)
	c.push_back(racks[n]);
      if(combo[n]=='0' || combo[n]==0)
	{
	  if(status[n]==1 || status[n]==4)
	    {
	      k.push_back(racks[n]);
	    }
	}
    }
  empty.addcombo(c);
  empty.addkeepalivecombo(k);
  empty.run.needssams=needssams;
  return empty;
}
