
#include "SphierStruct.h"
//#include "Array.h"
//#include "LinkedList.h"
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include "mpi.h"
//#include <ostream_iterator>
//#include "SphierIO"

//using namespace std;

char* itoa( int value, char* result, int base ) {
	
	// check that the base if valid
	
	if (base < 2 || base > 16) { *result = 0; return result; }
	

	
	char* out = result;
	
	int quotient = value;
	

	
	do {
	
		*out = "0123456789abcdef"[ std::abs( quotient % base ) ];
	
		++out;
	
		quotient /= base;
	
	} while ( quotient );
	

	
	// Only apply negative sign for base 10
	
	if ( value < 0 && base == 10) *out++ = '-';
	

	
	std::reverse( result, out );
	
	*out = 0;
	
	return result;
	
}

void Tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{

    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}
int main(int argc, char** argv)
{
   int numtasks, rank, rc; 
   rc = MPI_Init(&argc,&argv);
   if (rc != 0) {
     printf ("Error starting MPI program. Terminating.\n");
     MPI_Abort(MPI_COMM_WORLD, rc);
   }
   MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
   //cout<<"Number of tasks = "<< numtasks <<endl;//<<" My rank ="<< rank <<endl;
   //printf ("Number of tasks= %d My rank= %d\n", numtasks,rank);
  string line;
  // read the layer1 and layer0 node names
  char nameFilePrefix[] = "p";
  char nameFilePostfix[] = ".names";
  char myrank[10];
  double t1;
  double t2;
  itoa(rank,myrank,10);
  char nameFilev[50];
  strcpy(nameFilev,nameFilePrefix);
  strcat(nameFilev,myrank);
  strcat(nameFilev,nameFilePostfix);
  //cout<<"Data File ="<<dataFile<<endl;
  //ifstream myfile ("example.txt");
  //ifstream myfile(nameFilev);
  ifstream nameFile(nameFilev);
  int layer =0;
  int firstLine = 0;
  int size[2];
  SphierStruct* sp;
  //int size1 = 0;
  if (nameFile.is_open())
  {
    while (! nameFile.eof() )
    {
      getline (nameFile,line);
	  if(firstLine == 0){
          vector<string> sizes ;
		  Tokenize(line, sizes);
		  for(int i=0; i< 2; i++){
			  size[i] = atoi(sizes.at(i).c_str());
			  //cout<<"size["<<i<<"] = "<<size[i]<<endl;
		  }
		  //copy(sizes.begin(), sizes.end(), ostream_iterator<string>(cout, ", "));
         	  //cout <<endl;
		  firstLine = 1;
		   MPI_Comm dupl;
           MPI_Comm_dup(MPI_COMM_WORLD,&dupl);
           sp = new SphierStruct(size[0], size[1], 0, 1, 1, rank, &dupl);
	  }
	  else{
		// cout<<"size[0] ="<<size[0]<<endl; 
                 //sp = new SphierStruct(size[0], size[1]);
		 // cout<<"SP ID0= "<<sp->ID0<<endl;
	      string::size_type pos = line.find_first_of(".");
	      if(pos != string::npos){
		      line = line.substr(0,pos);
		      //cout<<"Line ="<<line<<endl;
		      vector<string> names;
		      Tokenize(line,names);
			  //copy(names.begin(), names.end(), ostream_iterator<string>(cout, ", "));
	          //cout <<endl;
			  for(unsigned int i=0; i < names.size(); i++){
				  //Node check(i,layer,names.at(i));
				  //sp->addNode(check);
				 // cout<<"before adding node"<<endl;
				  sp->addNode(names.at(i),layer);
				 //Node* check = sp->findNode(i,layer);
			     //cout<<"Adding node with name = "<<check->name<<" layer = "<<layer<<endl;
                                  //if(layer == 0) cout<<" and ID ="<<check->ID<<endl;
                                  //if(layer == 1)cout<<"and ID ="<<check->ID<<endl;
			  }
			  layer = 1;
			  //cout<<"Start reading Layer 1"<<endl;
	      }
		  else{
			  vector<string> names;
			  Tokenize(line, names);
			  //copy(names.begin(), names.end(), ostream_iterator<string>(cout, ", "));
	          //cout <<endl;
			  for(unsigned int i=0; i< names.size(); i++){
				  //Node temp = new Node();
				  //cout<<"before adding node"<<endl;
				  sp->addNode(names.at(i),layer);
				  //Node* check = sp->findNode(i,layer);
				  //cout<<"Adding node with name = "<<names.at(i)<<" layer = "<<layer<<endl;
			  }
		  }
	  }
	}
	nameFile.close();
        //sp->printStruct();
  }
  else cout<<"Unable to open the names file "<<endl;
  
  ofstream tfile;
  tfile.open("output.time");
  t1 = MPI_Wtime();
  char dataFilePrefix[] = "p";
  char dataFilePostfix[] = ".data";
  //char myrank[10];
  itoa(rank,myrank,10);
  char dataFile[50];
  strcpy(dataFile,dataFilePrefix);
  strcat(dataFile,myrank);
  strcat(dataFile,dataFilePostfix);
 // cout<<"Data File ="<<dataFile<<endl;
  //ifstream myfile ("example.txt");
  ifstream myfile(dataFile);
  if (myfile.is_open())
  {
    int index =0;
    while (! myfile.eof() )
    {
      getline (myfile,line);
      vector<string> tokens;
      Tokenize(line, tokens);
      //copy(tokens.begin(), tokens.end(), ostream_iterator<string>(cout, ", "));
      //cout<<endl;
	   Node* row = sp->findNode(index,0);
          // Array rowArray = sp->node0Array;
           //Node* row = &rowArray[index];
	  //cout<<"Found node layer = "<<row->layerNum<<" name = "<<row->name<<endl;
	  //cout<<"Working with Node index="<<index<<" name ="<<row->name<<" ID ="<<row->ID<<endl;
          //cout<<"tokens.size ="<<tokens.size()<<endl;
	  for(unsigned int i=0; i < tokens.size(); i++){
         int val = atoi(tokens.at(i).c_str());
		 if(val != 0 && val != -1){
			 Node* neighbor = sp->findNode(i,1);
			 pair<Node*, int> nb(neighbor, val);
			 pair<Node*, int> n2(row,1);
			 row->addNeighbor(nb);
			 neighbor->addNeighbor(n2);
			 //cout<<"Adding neighbor with name = "<<neighbor->name<<"and ID ="<<neighbor->ID<<" for node  "<<row->name<<endl;
		 }
	  }
	  //cout <<endl;
	   index = index+1;
    }
	
	t2 = MPI_Wtime();
	tfile<<"Time to initialize structure = "<< t2-t1<<endl;
	//sp->printStruct();
    //cout<<"Before Crossing Minimization"<<endl;
    sp->printMatrix(0);
	myfile.close();
	//getchar();
  }

   else cout << "Unable to open file";
   int count =0;  
   // perform crossing minimaztion using barycenter heuristic
   t1 = MPI_Wtime(); 
  do{
       MPI_Comm dup;
       MPI_Comm_dup(MPI_COMM_WORLD,&dup);
       sp->setPositionBary(sp->invertStaticLayer(), &dup);
       count++;
   //}while(sp->improvement != false);
   }while(count < 5);
   
   //tfile<<"Time to perform crossing minimization with iter=5 "<<t2-t1<<endl;
   //cout<<"After crossing minimization"<<endl;
   //t1=MPI_Wtime();
   sp->printMatrix(1);
   MPI_Barrier(MPI_COMM_WORLD);
   t2 = MPI_Wtime();
   if(rank == 0)
     cout<<t2-t1<<endl;
   //t2=MPI_Wtime();
   //tfile<<"Time toidentify biclusters and write to file "<<t2-t1<<endl; 
   //cout<<"Number of iterations = "<<count<<endl;
   MPI_Finalize();
}

//int main(int argc, char** argv)
//{
//  string line;
//  // read the layer1 and layer0 node names
//  ifstream nameFile ("data.names");
//  int layer =0;
//  int firstLine = 0;
//  int size[2];
//  SphierStruct* sp;
//  //int size1 = 0;
//  if (nameFile.is_open())
//  {
//    while (! nameFile.eof() )
//    {
//      getline (nameFile,line);
//	  if(firstLine == 0){
//                  vector<string> sizes ;
//		  Tokenize(line, sizes);
//		  for(int i=0; i< 2; i++){
//			  size[i] = atoi(sizes.at(i).c_str());
//			  //cout<<"size["<<i<<"] = "<<size[i]<<endl;
//		  }
//		  //copy(sizes.begin(), sizes.end(), ostream_iterator<string>(cout, ", "));
//          //cout <<endl;
//		  firstLine = 1;
//                  sp = new SphierStruct(size[0], size[1]);
//	  }
//	  else{
//		// cout<<"size[0] ="<<size[0]<<endl; 
//                 //sp = new SphierStruct(size[0], size[1]);
//		 // cout<<"SP ID0= "<<sp->ID0<<endl;
//	      string::size_type pos = line.find_first_of(".");
//	      if(pos != string::npos){
//		      line = line.substr(0,pos);
//		      //cout<<"Line ="<<line<<endl;
//		      vector<string> names;
//		      Tokenize(line,names);
//			  //copy(names.begin(), names.end(), ostream_iterator<string>(cout, ", "));
//	          //cout <<endl;
//			  for(unsigned int i=0; i < names.size(); i++){
//				  //Node check(i,layer,names.at(i));
//				  //sp->addNode(check);
//				  sp->addNode(names.at(i),layer);
//				 // Node* check = sp->findNode(i,layer);
//			// cout<<"Adding node with name = "<<check->name<<" layer = "<<layer<<endl;
//                                  //if(layer == 0) cout<<" and ID ="<<check->ID<<endl;
//                                  //if(layer == 1)cout<<"and ID ="<<check->ID<<endl;
//			  }
//			  layer = 1;
//			  //cout<<"Start reading Layer 1"<<endl;
//	      }
//		  else{
//			  vector<string> names;
//			  Tokenize(line, names);
//			  //copy(names.begin(), names.end(), ostream_iterator<string>(cout, ", "));
//	          //cout <<endl;
//			  for(unsigned int i=0; i< names.size(); i++){
//				  //Node temp = new Node();
//				  sp->addNode(names.at(i),layer);
//				  //Node* check = sp->findNode(i,layer);
//				  //cout<<"Adding node with name = "<<check->name<<" layer = "<<layer<<endl;
//			  }
//		  }
//	  }
//	}
//	nameFile.close();
//    //sp->printStruct();
//  }
//  else cout<<"Unable to open the names file "<<endl;
//
//  ifstream myfile ("data.data");
//  if (myfile.is_open())
//  {
//    int index =0;
//    while (! myfile.eof() )
//    {
//      getline (myfile,line);
//      vector<string> tokens;
//      Tokenize(line, tokens);
//      //copy(tokens.begin(), tokens.end(), ostream_iterator<string>(cout, ", "));
//      //cout<<endl;
//	   Node* row = sp->findNode(index,0);
//          // Array rowArray = sp->node0Array;
//           //Node* row = &rowArray[index];
//	  //cout<<"Found node layer = "<<row->layerNum<<" name = "<<row->name<<endl;
//	  //cout<<"Working with Node index="<<index<<" name ="<<row->name<<" ID ="<<row->ID<<endl;
//          //cout<<"tokens.size ="<<tokens.size()<<endl;
//	  for(unsigned int i=0; i < tokens.size(); i++){
//         int val = atoi(tokens.at(i).c_str());
//         //cout<<"value of the neighbor is "<<val<<endl;
//		 if(val != 0){
//			 Node* neighbor = sp->findNode(i,1);
//			 pair<Node*, int> nb(neighbor,val);
//			 //neighbor->setValue(val);
//			 row->addNeighbor(nb);
//			 pair< Node*,int> n(row,1);
//			 neighbor->addNeighbor(n);
//			 //cout<<"Adding neighbor with name = "<<neighbor->name<<"and ID ="
//			   //  <<neighbor->ID <<" value ="<<neighbor->value<<" for node  "<<row->name<<endl;
//		 }
//	  }
//	  //cout <<endl;
//	   index = index+1;
//    }
//	
//	//sp->printStruct();
//    cout<<"Before Crossing Minimization"<<endl;
//    sp->printMatrix(0);
//	myfile.close();
//	//getchar();
//  }
//
//   else cout << "Unable to open file";
//   int count =0;  
//   // perform crossing minimaztion using barycenter heuristic 
//  do{
//       sp->setPositionBary();
//       count++;
//   }while(count < 5);
// 
//   cout<<"After crossing minimization"<<endl;
//   sp->printMatrix(1); 
//   cout<<"Number of iterations = "<<count<<endl;
//   
//}
