/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    MoleCuilder is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/*
 * ConfigFileBuffer.cpp
 *
 *  Created on: 12.06.2010
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
//#include "CodePatterns/MemDebug.hpp"
#include 
#include 
#include 
#include "ConfigFileBuffer.hpp"
#include "CodePatterns/Verbose.hpp"
#include "CodePatterns/Log.hpp"
#include "Helpers/defs.hpp"
#include "Helpers/helpers.hpp"
#include "World.hpp"
/******************************** Functions for class ConfigFileBuffer **********************/
/** Structure containing compare function for Ion_Type sorting.
 */
struct IonTypeCompare {
  bool operator()(std::string s1, std::string s2) const {
    ConvertTo toInt;
    boost::char_separator sep("_");
    tokenizer tokens1(s1,sep);
    tokenizer tokens2(s2,sep);
    tokenizer::iterator tok_iter1 = tokens1.begin();
    tokenizer::iterator tok_iter2 = tokens2.begin();
    ++tok_iter1;
    ++tok_iter2;
    std::string element1(*tok_iter1++);
    std::string element2(*tok_iter2++);
    int elementno1 = toInt(element1.substr(4,string::npos));
    int elementno2 = toInt(element2.substr(4,string::npos));
    if (elementno1 != elementno2)
      return elementno1 < elementno2;
    else {
      std::string atom1(*tok_iter1);
      std::string atom2(*tok_iter2);
      int atomno1 = toInt(atom1);
      int atomno2 = toInt(atom2);
      return atomno1 < atomno2;
    }
//    char number1[8];
//    char number2[8];
//    const char *dummy1 = s1.c_str();
//    const char *dummy2 = s2.c_str();
//    //LOG(0, s1 << "  " << s2);
//    dummy1 = strchr(s1, '_')+sizeof(char)*5;  // go just after "Ion_Type"
//    dummy2 = strchr(dummy1, '_');
//    strncpy(number1, dummy1, dummy2-dummy1); // copy the number
//    number1[dummy2-dummy1]='\0';
//    dummy1 = strchr(s2, '_')+sizeof(char)*5;  // go just after "Ion_Type"
//    dummy2 = strchr(dummy1, '_');
//    strncpy(number2, dummy1, dummy2-dummy1); // copy the number
//    number2[dummy2-dummy1]='\0';
//    if (atoi(number1) != atoi(number2))
//      return (atoi(number1) < atoi(number2));
//    else {
//      dummy1 = strchr(s1, '_')+sizeof(char);
//      dummy1 = strchr(dummy1, '_')+sizeof(char);
//      dummy2 = strchr(dummy1, ' ') < strchr(dummy1, '\t') ? strchr(dummy1, ' ') : strchr(dummy1, '\t');
//      strncpy(number1, dummy1, dummy2-dummy1); // copy the number
//      number1[dummy2-dummy1]='\0';
//      dummy1 = strchr(s2, '_')+sizeof(char);
//      dummy1 = strchr(dummy1, '_')+sizeof(char);
//      dummy2 = strchr(dummy1, ' ') < strchr(dummy1, '\t') ? strchr(dummy1, ' ') : strchr(dummy1, '\t');
//      strncpy(number2, dummy1, dummy2-dummy1); // copy the number
//      number2[dummy2-dummy1]='\0';
//      return (atoi(number1) < atoi(number2));
//    }
  }
  typedef boost::tokenizer > tokenizer;
};
/** Constructor for ConfigFileBuffer class.
 */
ConfigFileBuffer::ConfigFileBuffer() :
    buffer(NULL),
    LineMapping(NULL),
    CurrentLine(0),
    NoLines(0)
{
};
/** Constructor for ConfigFileBuffer class with filename to be parsed.
 * \param *filename file name
 */
ConfigFileBuffer::ConfigFileBuffer(const char * const filename) :
    buffer(NULL),
    LineMapping(NULL),
    CurrentLine(0),
    NoLines(0)
{
  InitFileBuffer(filename);
}
void ConfigFileBuffer::InitFileBuffer(const char * const filename)
{
  ifstream *file= new ifstream(filename);
  InitFileBuffer(file);
}
void ConfigFileBuffer::InitFileBuffer(istream *file)
{
  char line[MAXSTRINGSIZE];
  RemoveMapping();
  // prescan number of lines
  if (file->fail()) {
    ELOG(1, "config file missing!");
    return;
  }
  NoLines = 0; // we're overcounting by one
  long file_position = file->tellg(); // mark current position
  while (file->good()) {
    file->getline(line, MAXSTRINGSIZE-1);
    NoLines++;
  }
  file->clear();
  file->seekg(file_position, ios::beg);
  LOG(1, NoLines-1 << " lines were recognized.");
  // allocate buffer's 1st dimension
  if (buffer != NULL) {
    ELOG(1, "FileBuffer->buffer is not NULL!");
    return;
  } else
    buffer = new char *[NoLines];
  // scan each line and put into buffer
  int lines=0;
  int i;
  do {
    buffer[lines] = new char[MAXSTRINGSIZE];
    file->getline(buffer[lines], MAXSTRINGSIZE-1);
    i = strlen(buffer[lines]);
    buffer[lines][i] = '\n';
    buffer[lines][i+1] = '\0';
    lines++;
  } while((!file->eof()) && (lines < NoLines));
  LOG(1, lines-1 << " lines were read into the buffer.");
  file->clear();
  file->seekg(file_position, ios::beg);
  InitMapping();
}
/** Destructor for ConfigFileBuffer class.
 */
ConfigFileBuffer::~ConfigFileBuffer()
{
  RemoveBuffer();
  RemoveMapping();
}
/** Create trivial mapping.
 */
void ConfigFileBuffer::InitMapping()
{
  LineMapping = new int[NoLines];
  for (int i=0;i IonTypeLineMap;
  if (!MappingAllocated) {
    InitMapping();
  }
  typedef boost::tokenizer >
      tokenizer;
  boost::char_separator sep("\t ");
  // put all into hashed map
  for (int i=CurrentLine; i (token, i));
      }
    }
  }
  // fill map (aka IonType1_1, IonType1_1, IonType1_1, IonType1_2, IonType1_2, IonType1_2, ...
  // ..., IonType2_1, IonType2_1, IonType2_1, ...)
  int nr=0;
  for (map::iterator runner = IonTypeLineMap.begin(); runner != IonTypeLineMap.end(); ++runner) {
    if (CurrentLine+nr < NoLines)
      LineMapping[CurrentLine+(nr++)] = runner->second;
    else {
      ELOG(0, "config::MapIonTypesInBuffer - NoLines is wrong: We are past the end of the file!");
      performCriticalExit();
    }
  }
}