#include <string>
#include <iostream>
#include <vector>

#include "pBlockPointer.h"

#define VAR_SIZE 4

using std::cout;
using std::endl;
using std::string;

// Returns the address of the block named sin the buffer _pbuf
char* pBlockPointer::BlockAddress(const std::string& s){ 
  return _pbuf+BlockInd(s);
}
char* pBlockPointer::BlockAddressR(const std::string& s){ 
  return _pbr+BlockInd(s);
}

 
// Returns the pointer to the buffer to be passed to HBOOK routines
char* pBlockPointer::CreatePbuf() {
  if(!(_pbuf==0)) { 
    cout<< " pBlockPointer::CreatePbuf: deleting _pbuf" << endl;
    delete [] _pbuf; 
  }  
  if(!(_pbr==0)) { 
    cout<< " pBlockPointer::CreatePbuf: deleting _pbr" << endl;
    delete [] _pbr; 
  }  
  _pbuf=new char[TotBufSize()]; 
  _pbr=new char[TotBufSize()]; 
  return _pbuf;
}

// Returns the size, in Byte, of the buffer
int pBlockPointer::TotBufSize(){  
  int temp=0;
  for (int i=0; i< _pblockmap.size(); temp+=_pblockmap[i++].nbyte);
  return temp;
}  

// Does count the number of bytes associated with the block s 
int& pBlockPointer::CountByte(const std::string& s)
{
  for (int i=0; i< _pblockmap.size(); i++)
    if( s== _pblockmap[i].name) return _pblockmap[i].nbyte;
  
  pBlockDesc p(s, 0, 0);
  _pblockmap.push_back(p);
  
  return _pblockmap[_pblockmap.size()-1].nbyte;
}

// Does count the number of bytes associated with the block s 
int& pBlockPointer::CountVar(const std::string& s)
{
  for (int i=0; i< _pblockmap.size(); i++)
    if( s== _pblockmap[i].name) return _pblockmap[i].nvar;
  
  pBlockDesc p(s, 0, 0);
  _pblockmap.push_back(p);
  
  return _pblockmap[_pblockmap.size()-1].nvar;
}
// Does count the number of bytes associated with the block s 
int& pBlockPointer::SetMult(const std::string& s)
{
  for (int i=0; i< _pblockmap.size(); i++)
    if( s== _pblockmap[i].name) return _pblockmap[i].nmult;
  
  pBlockDesc p(s, 0, 0);
  _pblockmap.push_back(p);
  
  return _pblockmap[_pblockmap.size()-1].nmult;
}

// Return the index in the buffer corresponding to the block
int pBlockPointer::BlockInd(const std::string& s)
{
  int temp=0;
  for (int i=0; i< _pblockmap.size(); ++i) {
    if( s== _pblockmap[i].name) {
      break;
    } else {
      temp+=_pblockmap[i].nbyte;
    }
  }
  return temp;    
}

pBlockDesc* pBlockPointer::GetBlockDesc(const std::string& s)
{
  for (int i=0; i< _pblockmap.size(); ++i) {
    if( s== _pblockmap[i].name) {
      return &_pblockmap[i];
    }
  }
  return new pBlockDesc("NULL",0,0);    
  
}

void pBlockPointer::Print(){

  cout << "  Blocks found : " << _pblockmap.size() << endl;
  cout << "|    B Name    |    B Size(Byte)   |   B Nvar   |  B Mult  |" 
       << endl;
  cout << "------------------------------------------------------------" 
       << endl;
  for (pBlockMap::const_iterator p=_pblockmap.begin(); p!=_pblockmap.end(); ++p)
    {
      cout << p->name << " | " << p->nbyte << " | " << p->nvar << " | " << 
	p->nmult << endl;
    }
}

char * pBlockPointer::BuffReorder(){
  char* temp=_pbuf;
  char* tempr=_pbr;
  char* junk;
//   for (pBlockMap::const_iterator p=_pblockmap.begin(); 
//        p!=_pblockmap.end(); ++p)
  for (int i=0; i<_pblockmap.size(); ++i)
    {
      if(_pblockmap[i].nmult==1){
	for(int j=0;j<_pblockmap[i].nbyte;++j) *tempr++=*temp++;
      } else {
	for(int j=0;j<VAR_SIZE;++j) *tempr++=*temp++;
	//	char **tt=new char*[p->nvar-1];
	char *tt[_pblockmap[i].nvar-1];
	cout << " Det: " << _pblockmap[i].name << ", " << 
	  _pblockmap[i].nvar << endl;
	for(int j=0;j<(_pblockmap[i].nvar-1);++j){
	  tt[j]=temp+VAR_SIZE*j*_pblockmap[i].nmult;
	  cout << " tt: " << std::hex << (long int) tt[j] <<
	    ", val:" << (long int)(temp+VAR_SIZE*j*_pblockmap[i].nmult) << ", " << 
	    (long int)_pbuf << 
	    ", " << (long int ) temp << 
	    ", " << j << ", " << _pblockmap[i].nmult << std::dec << endl;
	}
	for(int j=0;j<(_pblockmap[i].nmult);++j) {
	  for(int k=0;k<(_pblockmap[i].nvar-1);++k){
	    junk=tt[k];
	    for(int b=0; b<VAR_SIZE; ++b) *tempr++=*junk++;
	    tt[k]=junk;
	  }
	}
	temp+=(_pblockmap[i].nbyte-VAR_SIZE);
      }
    }
  return _pbr;
}
