#include "classad_package.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>

bool do_hole_plugging();
int readFileIntoString(char*, char*, int);

int main(int argc, char* argv[]){
  if(do_hole_plugging()){
    fprintf(stdout, "Do Hole Plugging\n");
  }
  else{
    fprintf(stdout, "Don't Do Hole Plugging\n");
  }
  return 0;
}

bool do_hole_plugging(){
  int blockSize, blocksPerSeg, candidateSegmentsRead, liveBlocks, emptyBlocks,
    transferTimeSeg, transferTimeBlock;

  //  PrettyPrint pp;
  ClassAdParser   parser;
  ClassAd         *policyAd;
  ClassAd         *contextAd;
  Value val;
  bool result;

  // timings
  struct timeval *time1 = (struct timeval *) malloc(sizeof(struct timeval));
  struct timeval *time2 = (struct timeval *) malloc(sizeof(struct timeval));
  struct timeval *time3 = (struct timeval *) malloc(sizeof(struct timeval));
  struct timezone *tz = (struct timezone *) malloc(sizeof(struct timezone));

  // read classad files
  int MAX = 5000;
  char policyString[MAX];
  char contextString[MAX];
  
  gettimeofday(time1,tz);

  readFileIntoString("user_classad", policyString, MAX);
  readFileIntoString("cleaner.log", contextString, MAX);

  gettimeofday(time2,tz);

  // debug
  //  cout << policyString << endl;
  //  cout << contextString << endl;

  // parse classads
  if(!(policyAd = parser.ParseClassAd(policyString))){
    fprintf(stderr, "error reading policy classad\n");
    exit(1);
  }
  if(!(contextAd = parser.ParseClassAd(contextString))){
    fprintf(stderr, "error reading context classad\n");
    exit(1);
  }

  // lookup values in context ad
  if(!(contextAd->EvaluateAttrInt("BlockSize", blockSize)) ||
     !(contextAd->EvaluateAttrInt("BlocksPerSeg", blocksPerSeg)) ||
     !(contextAd->EvaluateAttrInt("CandidateSegmentsRead", candidateSegmentsRead)) ||
     !(contextAd->EvaluateAttrInt("LiveBlocks", liveBlocks)) ||
     !(contextAd->EvaluateAttrInt("EmptyBlocks", emptyBlocks)) ||
     !(contextAd->EvaluateAttrInt("TransferTimeSeg", transferTimeSeg)) ||
     !(contextAd->EvaluateAttrInt("TransferTimeBlock", transferTimeBlock))){
    fprintf(stderr, "error evaluating attributes\n");
    exit(1);
  }

  // insert context values into policy ad
  if(!(policyAd->InsertAttr("BlockSize", blockSize)) ||
     !(policyAd->InsertAttr("BlocksPerSeg", blocksPerSeg)) ||
     !(policyAd->InsertAttr("CandidateSegmentsRead", candidateSegmentsRead)) ||
     !(policyAd->InsertAttr("LiveBlocks", liveBlocks)) ||
     !(policyAd->InsertAttr("EmptyBlocks", emptyBlocks)) ||
     !(policyAd->InsertAttr("TransferTimeSeg", transferTimeSeg)) ||
     !(policyAd->InsertAttr("TransferTimeBlock", transferTimeBlock))){
    fprintf(stderr, "error inserting attributes\n");
    exit(1);
  }

  // debug
  /*  string buffer1;
  pp.Unparse(buffer1, policyAd);
  cout << buffer1 << endl;

  if(!(policyAd->EvaluateAttr("TransferTimeCleaning", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer2;
  pp.Unparse(buffer2, val);
  cout << "TransferTimeCleaning:" << buffer2 << endl;

  if(!(policyAd->EvaluateAttr("SpaceFreedCleaning", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer3;
  pp.Unparse(buffer3, val);
  cout << "SpaceFreedCleaning:" << buffer3 << endl;

  if(!(policyAd->EvaluateAttr("TransferTimeHP", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer4;
  pp.Unparse(buffer4, val);
  cout << "TransferTimeHP:" << buffer4 << endl;

  if(!(policyAd->EvaluateAttr("SpaceFreedHP", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer5;
  pp.Unparse(buffer5, val);
  cout << "SpaceFreedHP:" << buffer5 << endl;

  if(!(policyAd->EvaluateAttr("CostBenefitCleaning", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer6;
  pp.Unparse(buffer6, val);
  cout << "CostBenefitCleaning:" << buffer6 << endl;

  if(!(policyAd->EvaluateAttr("CostBenefitHP", val))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }
  string buffer7;
  pp.Unparse(buffer7, val);
  cout << "CostBenefitHP:" << buffer7 << endl;
  */

  // Evaluate StartHolePlugging expression
  if(!(policyAd->EvaluateAttrBool("StartHolePlugging", result))){
    fprintf(stderr, "error evaluating classad\n");
    exit(1);
  }

  gettimeofday(time3,tz);

  long file_time = (time2->tv_sec - time1->tv_sec)*100000 +
    (time2->tv_usec - time1->tv_usec);
  long classad_time = (time3->tv_sec - time2->tv_sec)*100000 +
    (time3->tv_usec - time2->tv_usec);
    
  fprintf(stdout,"time to read files: %ld \n", file_time);
  fprintf(stdout,"time to build and eval classad: %ld \n", classad_time);

  if(result == true){
    return true;
  }
  else{
    return false;
  }
}


int readFileIntoString(char* fileName, char* resultString, int size){
  // this is a retarded way to read the file, but it works.
  int fd = open(fileName, O_RDONLY);
  if(fd < 0){
    cerr << "couldn't open" << fileName << endl;
    exit(1);
  }
  int nread = read(fd, resultString, size);
  if(nread < 0){
    cerr << "couldn't read" << fileName << endl;
    exit(1);
  }    
  close(fd);
  resultString[nread] = '\0';
  return 0;
}



