#include "resultset.h"
#include "structs.h"
#include "totals.h"
#include "rack.h"
#include <string>
#include <iostream>
#include <fstream>
#include <vector>

#define HOST "127.0.0.1"
#define USER "root"
#define PASS "blah"
#define DATADB "plum_data"
#define OUTPUTDB "plum_output"

using namespace std;

void getParams(MYSQL conn,int& numracks,Run& run,int runidx,vector<Rack>& racks);
int get50Point(MYSQL db,int order,string tblname);
vector<string> getSelects(MYSQL conn,string tblname,int point); // Return a vector of all the combinations
vector<Totals> calcTotals(vector<Rack> racks,vector<string> data); // Return a vector of all the totals, including totals by partner, for combinations
vector<Average> calcAverages(vector<Totals> totals,Run run,Average& allusage,int point); // Find average resource use by partner, and average percent of capability used.

// FIXME This is godawful. Please make it not hurt so much to look at.
vector<Totals> totals;
Average allusage;
vector<Average> averages;
int point;

void boxBuild(int runidx){
  int numracks;
  Run run;
  vector<Rack> racks;
  MYSQL plum_data=ResultSet::makeConn(HOST,USER,PASS,DATADB);
  MYSQL plum_output=ResultSet::makeConn(HOST,USER,PASS,OUTPUTDB);
  getParams(plum_data,numracks,run,runidx,racks);
  point=get50Point(plum_output,run.numcombos/2,run.tblname);
  totals=calcTotals(racks,getSelects(plum_output,run.tblname,point));
  averages=calcAverages(totals,run,allusage,point);
}



int numPartners(){
  return averages.size();
}


void writePartnerTable(ostream& out){

  out<<"RESOURCESX TEXTCELL add RESOURCESY 1 (Total) [\n";
  out<<"("<<(allusage.count==allusage.count?allusage.count:0)<<")\n";
  out<<"("<<(allusage.crewtrng==allusage.crewtrng?allusage.crewtrng:0)<<")\n";
  out<<"("<<(allusage.middecks==allusage.middecks?allusage.middecks:0)<<")\n";
  out<<"("<<(allusage.upmass==allusage.upmass?allusage.upmass:0)<<")\n";
  out<<"("<<(allusage.stowage==allusage.stowage?allusage.stowage:0)<<")\n";
  out<<"("<<(allusage.keepalive==allusage.keepalive?allusage.keepalive:0)<<")\n";
  out<<"("<<(allusage.MTL==allusage.MTL?allusage.MTL:0)<<")\n";
  out<<"("<<(allusage.acoustics==allusage.acoustics?allusage.acoustics:0)<<")\n";
  out<<"("<<(allusage.energy==allusage.energy?allusage.energy:0)<<")\n";
  out<<"("<<(allusage.crewtime==allusage.crewtime?allusage.crewtime:0)<<")\n";
  out<<"] tableColumn\n\n";

  for(int n=0;n!=averages.size();n++)
    {
      out<<"RESOURCESX TEXTCELL add NUMBERCELL "<<(n+1)<<" mul add RESOURCESY 1 ("<<Totals::partners[n]<<") [\n";
      out<<"("<<averages[n].count<<")\n";
      out<<"("<<averages[n].crewtrng<<")\n";
      out<<"("<<averages[n].middecks<<")\n";
      out<<"("<<averages[n].upmass<<")\n";
      out<<"("<<averages[n].stowage<<")\n";
      out<<"("<<averages[n].keepalive<<")\n";
      out<<"("<<averages[n].MTL<<")\n";
      out<<"("<<averages[n].acoustics<<")\n";
      out<<"("<<averages[n].energy<<")\n";
      out<<"("<<averages[n].crewtime<<")\n";
      out<<"] tableColumn\n\n";
    }

}





vector<Average> calcAverages(vector<Totals> totals,Run run,Average& allusage,int point){
  vector<Average> partnerusage;
  partnerusage.reserve(Totals::partners.size());
  Totals allcombos;
  double running=0;

  for(int n=0;n!=totals.size();n++)
    allcombos+=totals[n];

  // Calculate percentage of maximum used by all partners together
  allusage.count=100.0;
  allusage.upmass=allcombos.upmass/(run.upmass*totals.size())*100.0;
  allusage.crewtrng=allcombos.crewtrng/(run.crewtrng*totals.size())*100.0;
  allusage.crewtime=allcombos.crewtime/(run.crewtime*totals.size())*100.0;
  allusage.energy=allcombos.energy/(run.energy*totals.size())*100.0;
  allusage.middecks=allcombos.middecks/(run.middecks*totals.size())*100.0;
  allusage.stowage=allcombos.stowage/(run.stowage*totals.size())*100.0;
  allusage.keepalive=allcombos.keepalive/(run.keepalive*totals.size())*100.0;
  allusage.MTL=allcombos.MTL/(run.MTL*totals.size())*100.0;  
  allusage.acoustics=allcombos.acoustics/(run.acoustics*totals.size())*100.0;

  //cout<<"num: "<<(allcombos.MTL/totals.size())<<'\n'<<"den: "<<run.MTL<<'\n';

  for(int n=0;n!=Totals::partners.size();n++) // Calculate average total usage of all resources for each partner
    {
      Average a;
      // This mess is all to make sure that a div by zero results in zero.
      if(allcombos.count!=0.0)a.count=allcombos.count_partners[n]/allcombos.count*100.0;
      if(allcombos.upmass!=0.0)a.upmass=allcombos.upmass_partners[n]/allcombos.upmass*100.0;
      if(allcombos.crewtrng!=0.0)a.crewtrng=allcombos.crewtrng_partners[n]/allcombos.crewtrng*100.0;
      if(allcombos.crewtime!=0.0)a.crewtime=allcombos.crewtime_partners[n]/allcombos.crewtime*100.0;
      if(allcombos.energy!=0.0)a.energy=allcombos.energy_partners[n]/allcombos.energy*100.0;
      if(allcombos.middecks!=0.0)a.middecks=allcombos.middecks_partners[n]/allcombos.middecks*100.0;
      if(allcombos.stowage!=0.0)a.stowage=allcombos.stowage_partners[n]/allcombos.stowage*100.0;
      if(allcombos.keepalive!=0.0)a.keepalive=allcombos.keepalive_partners[n]/allcombos.keepalive*100.0;
      if(allcombos.MTL!=0.0)a.MTL=allcombos.MTL_partners[n]/allcombos.MTL*100.0;
      if(allcombos.acoustics!=0.0)a.acoustics=allcombos.acoustics_partners[n]/allcombos.acoustics*100.0;
      partnerusage.push_back(a);
    }
  return partnerusage;
}





vector<Totals> calcTotals(vector<Rack> racks,vector<string> data){
  vector<Totals> totals;
  totals.reserve(data.size());
  for(int d=0;d!=data.size();d++)
    {
      Totals combo;
      string selects=data[d];
      if(selects.size()!=racks.size())
	{
	  cout<<"Selection string is the wrong size. Possible data corruption?\n";
	  exit(1);
	}
      for(int r=0;r!=selects.size();r++)
	{
	  if(selects[r]=='1')
	    {
	      Rack rack=racks[r];
	      combo+=rack;
	    }
	}
      totals.push_back(combo);
    }
  return totals;
}





vector<string> getSelects(MYSQL conn,string tblname,int point){
  ResultSet selects(&conn);
  selects.query<<"select selects from "<<tblname<<" where selectednum="<<point<<" and any_exceeded_inc=0";
  selects.store();
  vector<string> data;
  data.reserve(selects.size());
  if(selects.size()!=0)
    while(selects.next())
      data.push_back(selects[0]);
  return data;
}







void getParams(MYSQL conn,
	       int& numracks,
	       Run& run,
	       int runidx,
	       vector<Rack>& racks
	       ){
  ResultSet res(&conn);
  res.query<<"select count(idx) as num from racks";
  res.store();res.next();
  numracks=res["num"];

  res.query<<"select * from runs where idx="<<runidx;
  res.store();res.next();
  run.min=res["min"];
  run.max=res["max"];
  run.numcombos=res["numcombos"];
  run.idx=res["idx"];
  run.tblname=(string)res["tblname"];
  run.inclength=res["inclength"];
  run.upmass=res["upmass"]-res["bulk"];
  run.crewtrng=res["crewtrng"];
  run.crewtime=res["crewtime"]*res["inclength"]/7.0;
  run.middecks=res["MLE"];
  run.stowage=res["stowage"]*16.0; // FIXME 16
  run.keepalive=res["keepalive"]-res["hskpg"];
  run.energy=res["power"]*res["inclength"]*24;
  Rack::inclength=run.inclength;
  Rack::middeckmass=res["middeckmass"];
  Rack::rack_overhead=res["rack_overhead"];

//   res.query<<"select sum(modules.MTL_total)*runs.inclength*24 as MTL_max, "
// 	   <<"sum(modules.acoustics)*runs.inclength*24 as acoustics "
// 	   <<"from racks,locations,modules,runs where runs.idx="<<runidx<<" and "
// 	   <<"racks.location=locations.idx and locations.module=modules.idx";

  res.query<<"select sum(modules.MTL_total)*runs.inclength*24 as MTL_max, "
	   <<"sum(modules.acoustics)*runs.inclength*24 as acoustics "
	   <<"from modules,runs where runs.idx="<<runidx;
  res.store();res.next();
  //run.acoustics=res["acoustics"];
  run.acoustics=run.inclength*24*17;
  run.MTL=res["MTL_max"];
  
  res.query<<"select racks.acronym from racks order by racks.idx asc";
  res.store();
  racks.reserve(res.size());
  while(res.next())
    {
      Rack r(conn,res[0]);
      racks.push_back(r);
    }

  res.query<<"select distinct partner from racks";
  res.store();
  while(res.next())
    Totals::partners.push_back(res[0]);
}









int get50Point(MYSQL db,int order,string tblname){
  ResultSet percents(&db);
  percents.query<<"select selectednum,count(idx) as percent from "
		<<tblname
		<<" where any_exceeded_inc=0 group by selectednum";
  percents.store();
  int best=0,target=0;
  if(percents.size()==0)
    {
      ResultSet res(&db);res.query<<"select min(selectednum) as min from "<<tblname;
      res.store();
      res.next();
      return res["min"];
    }
  if(percents.next())
    {
      best=(int)percents["percent"]-order;
      target=(int)percents["selectednum"];
      while(percents.next())
	{
	  int currentbest=(int)percents["percent"]-order;
	  if(abs(currentbest)<=abs(best))
	    {
	      best=currentbest;
	      target=(int)percents["selectednum"];
	    }
	}
    }
  return target;
}
