/* Take pp file generated by ppgen.3
* This is the format of the pp file:
*   A region tag must preceed its start and end tags with no other
*   tags in between:
*     region <region-id> <weight> <n-start-points> <n-end-points> <length> <icount-from-program-start>
*     slice <slice-id> <phase-id> <distance-from-centroid>
*     start <marked-instr-id> <execution-count-since-program-start> <icount-from-slice-start>
*     end   <marked-instr-id> <execution-count-since-program-start> <icount-from-slice-start>
*
*   A markedInstrs tag must preceed the mark tags.  There must be
*   exactly one markedInstrs tag in the file.
*     markedInstrs <n-marked-instrs>
*     mark <mark-id> <instr-address> <used-in-start> <used-in-end> <is-nop-instr>
*
*/

#include <iostream>
#include <fstream>
#include <string.h>
#include <list>
#include <utility>
using namespace std;
class Point {
public:
  int id;
  long unsigned int address;
  long unsigned int execount;
  bool symbolic;
  string lib_name;
  long unsigned int offset;
  string dump_content() {
    ostringstream ct;
    ct << "ID: " << id << " ADDRESS: " << address << " EXECOUNT: " << execount <<
      " SYMBOLIC: " << symbolic <<
      " LIB_NAME: " <<  lib_name << " OFFSET: " << offset << "\n";
      return ct.str();
  }
};
class PSlice {
public:
  int slice;
  double weight;
  Point * start = new Point();
  Point * end = new Point();
  string dump_content(){
    std::ostringstream content;
    content << "SLICE ID: " << slice << "\n";
    content << "WEIGHT: "  << weight << "\n";
    content << "START POINT: \n";
    content << start->dump_content();
    content << "END POINT: \n";
    content << end->dump_content();
    return content.str();
  }
};
class Parser {
public:
std::list<PSlice*> * slices= new std::list<PSlice*>();
void dump_content(FILE * outfile){
  for (std::list<PSlice*>::iterator it=slices->begin();it != slices->end();++it) {
    fprintf(outfile,"SLICE:\t%d\n%s\n", (*it)->slice, (*it)->dump_content().c_str());
  }
}
string dump_content(){
  std::ostringstream content;
  for (std::list<PSlice*>::iterator it=slices->begin();it != slices->end();++it) {
    content <<"SLICE:\t" << (*it)->slice << "\n" << (*it)->dump_content().c_str()<<std::endl;
  }
  return content.str();
}
PSlice * getFastPoint(){
  PSlice * fast = NULL;
  double fast_weight=0;
  for (std::list<PSlice*>::iterator it=slices->begin();it != slices->end();++it) {
    if(fast_weight < (*it)->weight) {
      fast = (*it);
      fast_weight = (*it)->weight;
    }
  }
  return fast;
}
void findAndUpdate(int id, long unsigned int address, bool symb, string name, long unsigned int offset) {
  for (std::list<PSlice*>::iterator it=slices->begin();it != slices->end();++it) {
    if((*it)->start->id == id) {
      (*it)->start->address = address;
      (*it)->start->lib_name = name;
      (*it)->start->offset = offset;
      (*it)->start->symbolic = symb;
    }
    if( (*it)->end->id == id) {
      (*it)->end->address = address;
      (*it)->end->lib_name = name;
      (*it)->end->offset = offset;
      (*it)->end->symbolic = symb;
    }
  }
}
void parse(string ifile){
  ifstream point_file(ifile.c_str());
  string line="";
  PSlice * current = NULL ;
  while(std::getline(point_file, line)) {
    char *token = strtok(strdup(line.c_str()), " ");
    while(token!=NULL) {
      if(strcmp(token,"#")==0) {
        std::getline(point_file, line);
        token = strtok(strdup(line.c_str()), " ");
        continue;
      }
      else if(strcmp(token,"#Pinpoint=")==0) {
        PSlice * n_slice = new PSlice();
        token = strtok(NULL," ");
        n_slice->slice = atoi(token);
        slices->push_back(n_slice);
        current=n_slice;
      }
      else if(strcmp(token,"region")==0) {
        token = strtok(NULL," "); //weight is not the first token after region
        token = strtok(NULL," "); //weight
        current->weight = atof(token);
      }
      else if(strcmp(token,"start")==0) {
        token = strtok(NULL," "); //start point id
        current->start->id = atoi(token);
        token = strtok(NULL," "); //start execution count
        current->start->execount = atol(token);
      }
      else if(strcmp(token,"end")==0) {
        token = strtok(NULL," "); //end point id
        current->end->id = atoi(token);
        token = strtok(NULL," "); //end execution count
        current->end->execount = atol(token);
      }
      else if (strcmp(token,"mark-symbolic")==0) {
        token = strtok(NULL," "); //point id
        int id = atoi(token);
        token = strtok(NULL," "); //address
        long unsigned int address;
        address = strtoul(token,NULL,0);
        token = strtok(NULL," "); // not needed
        token = strtok(NULL," "); // not needed
        token = strtok(NULL," "); // not needed
        token = strtok(NULL," "); // img name
        string img_name = token;
        token = strtok(NULL," "); // not needed
        //long unsigned int loadaddr = strtoul(token,NULL,0);
        token = strtok(NULL," "); // offset
        long unsigned int offset =strtoul(token,NULL,0);
        //printf("addr: %lu load: %lu offset: %lu calc_offset: %lu\n", address, loadaddr, offset, (address-loadaddr));
        findAndUpdate(id,address,1,img_name,offset);
      }
      else if (strcmp(token,"mark")==0 ){
        token = strtok(NULL," "); //point id
        int id = atoi(token);
        token = strtok(NULL," "); //address
        long unsigned int address;
        address = strtoul(token,NULL,0);
        findAndUpdate(id,address,0,"",0);
      }
      token = strtok(NULL," ");
    }
  }
  //slices->sort();
}
};
/*
int main(int argc, char** argv)
{
    if(argc<3) {
      printf("Should give arguments: <ppfilename>, <outputfilename>\n");
      exit(1);
    }
    Parser * ps = new Parser();
    ps->parse(argv[1]);
    string ofile = argv[2];
    FILE * outfile;
    outfile = fopen(ofile.c_str(),"w");
    ps->dump_content(outfile);
    return 0;
}*/
