/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#include "GenericShape.h"

#include <stdlib.h>
#include <fstream>

#ifdef DEBUG
#include <stdio.h>
#define DPRINT(...) printf("%s:%d ",__FUNCTION__,__LINE__);printf(__VA_ARGS__);
#else
#define DPRINT(...)
#endif /* DEBUG */



#define NEXTLINE \
  if ( valid == 1 ) { \
    if ( std::getline(infile,line).eof()) { \
      valid = 0; \
    } \
  }  

GenericShape::GenericShape(string fileDB, string name) {
  int valid;
  regex re;
  string line;
  std::ifstream infile(fileDB.c_str());
  valid = 1;  
  NEXTLINE
  try {
    // Find the shape in the file with the correct name
    re.assign("name=\"" + name + "\",");
    while ( (!regex_match(line,re)) && ( valid == 1)) {
      NEXTLINE // Find matching shape
    }
    if (regex_match(line,re)) {
      NEXTLINE // Will retrieve "sphereList = [" line
      NEXTLINE // Skip over "sphereList = [" line to first sphere
      // Extract out all following lines containing 4-tuples as origins and
      // radii
      regex retwo;
      retwo.assign("\\((-?[\\d\\.]+),(-?[\\d\\.]+),(-?[\\d\\.]+),([\\d\\.]+)\\),?");
      boost::cmatch matches;
      while (regex_match(line.c_str(),matches,retwo)) {
        string xstr(matches[1].first, matches[1].second);
        double x = strtod(xstr.c_str(),NULL);
        string ystr(matches[2].first, matches[2].second);
        double y = strtod(ystr.c_str(),NULL);
        string zstr(matches[3].first, matches[3].second);
        double z = strtod(zstr.c_str(),NULL);

        string rstr(matches[4].first, matches[4].second);
        double r = strtod(rstr.c_str(),NULL);

        if (( sqrt(x*x+y*y+z*z) <= 1.0f ) && ( r > 0 )) {
          Vector3 center(x,y,z);
          origins.push_back(center);
          radii.push_back(r);
        }
        NEXTLINE // Next line in file
      }

      NEXTLINE // Skip over "]" line
      NEXTLINE // Skip over "bondList = [" line

      // Extract out all following lines containing tuples as bonds.
      retwo.assign("\\((\\d+),(\\d+)\\),?");
      while (regex_match(line.c_str(),matches,retwo)) {
        string firststr(matches[1].first, matches[1].second);
        unsigned int first = atoi(firststr.c_str());
        string secondstr(matches[2].first, matches[2].second);
        unsigned int second = atoi(secondstr.c_str());
        if ((first <= radii.size()) &&( second <= radii.size()) &&
            (first != second)) {
          vector<int> bond;
          bond.push_back(first);
          bond.push_back(second);
          std::cout << "Pair added: " << first << ", " << second << std::endl;
          bonds.push_back(bond);
        }
        NEXTLINE
      }
      // At this point we simply assume the shape is now valid
      //
      valid = 1;
    }
  } catch (boost::regex_error& e) {
    std::cout << "Regexp failed:" << e.code() << std::endl;
  }
  if ( origins.size() != radii.size() ) {
    std::cout << "Parsed " << radii.size() << " radii and " << origins.size()
              << " origins.  Something broken.\n";
  }
  std::cout << "Parsed " << radii.size() << " spheres and " << bonds.size() 
            << " bonds.\n";
  if ( valid != 1 ) {
    std::cout << "Error parsing." << std::endl;  
    bonds.clear();
    radii.clear();
    origins.clear();
  }
  infile.close();
  return;
}



void GenericShape::insert(Vector3 pos, double radius, MNTable3D* table, int tag, int id) {
  int *ids;
  if ( ( ids = (int *)(malloc(radii.size()*sizeof(int)))) == NULL ) {
     std::cout << "Err:  Cannot allocate memory for IDs" << std::endl;
     return;
  }
  if ( this->useRandomOrientation() ) {
    this->setRandomOrientation();
  }
  unsigned int k;
  for(k=0;k<radii.size();k++){
    Vector3 offset=origins[k]*radius;
    Sphere Sk(pos + rotatePoint(offset),radius*radii[k]);
    if(table->checkInsertable(Sk,id)){
      Sk.setTag(this->getParticleTag());
      table->insert(Sk,id);
      ids[k] = Sk.Id();
    } else {
      ids[k] = 0;
    }
  }
  for(k=0;k<bonds.size();k++){
    vector<int> bondpair = bonds[k];
    int particleA = bondpair[0];
    int particleB = bondpair[1];
    if (( ids[particleA] == 0 )|| ( ids[particleB] == 0)) {
    } else {
      table->insertBond(ids[particleA],ids[particleB],this->getBondTag());
    }
  }
}  


int GenericShape::bias() {
  return Shape::bias();
}

void GenericShape::setBias(int i) {
  Shape::setBias(i);
}

