#include "fileIO.h"
#include <cstring>
#include <fstream>
#include <iostream>
#include <geometry.h>

//fonction qui charge un fichier STL
void loadmesh(std::string filename,stlmesh_nn &mesh)
{
  std::cout << " chargement de " << filename << " ... " << std::endl;
  mesh.load_stl(filename);
}


SBFileType checkSBFormat(std::string filename)
{
  std::ifstream fe;
  fe.open ( filename.c_str() );
  if ( !fe.fail() )
  {
    for (int i=0;i<10;++i)
    {
      std::string str;
      fe >> str;
      if (str.size()>7)
      {
        std::string substr=str.substr(str.size()-7,str.size());
        if (substr=="_Origin")
        {
          fe.close();
          return SBimetric;
        }
      }
    }
    fe.clear();
    fe.seekg(0,std::ios::beg);
    double scale;
    fe >> scale;
    if (fe.fail()&& !fe.eof())
    {
      fe.close();
      return SBother;
    }
    fe.close();
    return SBnative;
  }
  return SBother;
}

void loadSBimetric(std::string filename, std::vector<std::pair<npoint3,npoint3> >& sb)
{
  std::ifstream fe;
  std::string poub;
  std::cout << " chargement de " << filename << " (format SB Imetric) ... " << std::endl;
  fe.open ( filename.c_str() );
  bool ok=false;
  if ( !fe.fail() )
  {
      npoint3 p;
      npoint3 x,y,z,v;
      do
      {
        fe >> poub;
        if (poub.size()>7)
        {
          std::string substr=poub.substr(poub.size()-7,poub.size());
          if (substr=="_Origin") ok=true;
        }
      } while ((!ok)&&(!fe.eof()));
      if (ok)
      {
        fe >> p[0] >> p[1] >> p[2];
        fe >> poub >> x[0] >> x[1] >> x[2];
        fe >> poub >> y[0] >> y[1] >> y[2];
        fe >> poub >> z[0] >> z[1] >> z[2];
      }
      if ((fe.fail() && !fe.eof()) || (!ok))
      {
        std::cout << "error in file" << std::endl;
        sb.clear();
        throw 1;
      }
      for (int i=0;i<3;++i) v[i]=(z[i]-p[i])/10;
      v.normalize();
      while ( !fe.eof() )
      {
        if (ok) sb.push_back(std::make_pair(p,v));
        ok=false;
        do
        {
          fe >> poub;
          if (poub.size()>7)
          {
            std::string substr=poub.substr(poub.size()-7,poub.size());
            if (substr=="_Origin") ok=true;
          }
        } while ((!ok)&&(!fe.eof()));
        
        if (ok)
        {
          fe >> p[0] >> p[1] >> p[2];
          fe >> poub >> x[0] >> x[1] >> x[2];
          fe >> poub >> y[0] >> y[1] >> y[2];
          fe >> poub >> z[0] >> z[1] >> z[2];
        }

        if (fe.fail()&& !fe.eof())
        {
          std::cout << "error in file" << std::endl;
          sb.clear();
          throw 1;
        }
        if (ok)
        {
          for (int i=0;i<3;++i) v[i]=(z[i]-p[i])/10;
          v.normalize();
        }
      }
      fe.close();
  }
  else
  {
    std::cout << " fichier inexistant" << std::endl;
    throw 1;
  }
  std::cout << sb.size()  << " points."  << std::endl;
    
}

void loadSBNative(std::string filename, std::vector<std::pair<npoint3,npoint3> >& sb)
{
  std::ifstream fe;
  std::cout << " chargement de " << filename << " (format SB natif) ... " << std::endl;
  fe.open ( filename.c_str() );
  double scale;
  if ( !fe.fail() )
  {
      fe >> scale;
      npoint3 p;
      npoint3 v;
      fe >> p[0] >> p[1] >> p[2];
      for (int i=0;i<3;++i) p[i]*=scale;
      fe >> v[0] >> v[1] >> v[2];
      if (fe.fail()&& !fe.eof())
      {
        std::cout << "error in file" << std::endl;
        sb.clear();
        throw 1;
      }
      v.normalize();
      while ( !fe.eof() )
      {
        sb.push_back(std::make_pair(p,v));
        fe >> p[0] >> p[1] >> p[2];
        for (int i=0;i<3;++i) p[i]*=scale;
        fe >> v[0] >> v[1] >> v[2];
        v.normalize();
        if (fe.fail()&& !fe.eof())
        {
          std::cout << "error in file" << std::endl;
          sb.clear();
          throw 1;
        }
      }
      fe.close();
  }
  else
  {
    std::cout << " fichier inexistant" << std::endl;
    throw 1;
  }
  std::cout << sb.size()  << " points."  << std::endl;
}

void loadSB(std::string filename, std::vector<std::pair<npoint3,npoint3> >& sb)
{
  SBFileType sbt= checkSBFormat(filename);
  if (sbt==SBnative) loadSBNative(filename,sb);
  if (sbt==SBimetric) loadSBimetric(filename,sb);
  if (sbt==SBother) throw 0;
}

void saveSB(std::string filename, std::vector<std::pair<npoint3,npoint3> >& sb)
{
  std::ofstream fe;
  std::cout << " sauvegarde de " << filename << " ... " << std::endl;
  fe.open ( filename.c_str() );
  double scale=1.0;
  fe << scale << std::endl;
  for (int i=0;i<sb.size();++i)
  {
    fe << sb[i].first[0] << " " << sb[i].first[1] << " " << sb[i].first[2] << " " ;
    fe << sb[i].second[0] << " " << sb[i].second[1] << " " << sb[i].second[2] << std::endl;
  }
  fe.close();
  std::cout << sb.size()  << " points."  << std::endl;
}


void loadPoints(std::string filename, std::vector<std::pair<npoint3,npoint3> >& sb,std::vector<npoint3> &pts,double sbh)
{
  std::ifstream fe;
  std::cout << " chargement de " << filename << " ... " << std::endl;
  fe.open ( filename.c_str() );
  double scale=1.0;int nbsb=0;
  std::vector<std::vector<npoint3> > cyls;
  std::vector<std::vector<npoint3> > plas;
  
  if ( !fe.fail() )
  {
    fe >> scale;
    fe >> nbsb;
    if (!fe.eof() && !fe.fail() && nbsb<=65535)
    {
      cyls.resize(nbsb);
      plas.resize(nbsb);
    }
    else
    {
      std::cout << "error in file" << std::endl;
      nbsb=0;
      cyls.clear();
      plas.clear();
      throw 1;
    }
      
    npoint3 p;
    char type;
    int num;
    fe >> type;
    fe >> num;
    fe >> p[0] >> p[1] >> p[2];
    if (fe.fail()&& !fe.eof() && num<nbsb)
    {
      std::cout << "error in file" << std::endl;
      nbsb=0;
      cyls.clear();
      plas.clear();
      throw 1;
    }
    
    while ( !fe.eof() && !fe.fail())
    {
      for (int i=0;i<3;++i) p[i]*=scale;
      if (type=='c') cyls[num].push_back(p);
      if (type=='p') plas[num].push_back(p);
      pts.push_back(p);
      
      fe >> type; fe>>num;
      fe >> p[0] >> p[1] >> p[2];
      if (fe.fail()&& !fe.eof() && num<nbsb)
      {
        std::cout << "error in file" << std::endl;
        nbsb=0;
        cyls.clear();
        plas.clear();
        throw 1;
      }
    }
    fe.close();
    npoint3 normalc;
    npoint3 normalp;
    npoint3 basec;
    npoint3 basep;
    double radius;
    for(int i=0;i<nbsb;++i)
    {
      std::vector<npoint3> ptsout;
      get_cyl(cyls[i],basec,normalc,radius,ptsout,true);
      get_cyl_fine(cyls[i],basec,normalc,radius,ptsout,true,true);
      double angle;
//      get_cone(cyls[i],basec,normalc,angle,ptsout);
//      std::cout<< "angle" << angle << std::endl;
      get_plane(plas[i],basep,normalp,ptsout,false);
      npoint3 res;
      int_line_plane(basec, normalc, basep, normalp, res);
      npoint3 orinor=res-basec;
      orinor.normalize();
      npoint3 vec=orinor*sbh;
      res-=vec;
      std::cout << "base point : [ "
        << res[0] << " , "
        << res[1] << " , "
        << res[2] << " ]" << std::endl;

      std::cout << "normal : [ "
        << orinor[0] << " , "
        << orinor[1] << " , "
        << orinor[2] << " ]" << std::endl;
      //      std::pair<npoint3,npoint3> sc(res,orinor);
      if (orinor.dotprod(normalp)<0) normalp*=-1;
      std::pair<npoint3,npoint3> sc(res,normalp);
      sb.push_back(sc);      

/*      int_line_plane(basec, normalc, basep, normalp, res);
      npoint3 orinor=res-basec;
      orinor.normalize();
      npoint3 vec=orinor*sbh;
      res-=vec;
      std::cout << "normal = "
      << orinor[0] << " "
      << orinor[1] << " "
      << orinor[2] << std::endl;
      std::pair<npoint3,npoint3> sc(res,orinor);*
      sb.push_back(sc);*/
    }
  }
  else
  {
    std::cout << " fichier inexistant" << std::endl;
    throw 1;
  }
  std::cout << sb.size()  << " points."  << std::endl;
}



