// GenFem - A high-level finite element library
// Copyright (C) 2010-2026 Eric Bechet
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//
// Initial design: Eric Bechet (rev.734)


#ifndef _GENDATAIO_H_
#define _GENDATAIO_H_

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

#include "genMatrix.h"
#include "genTensors.h"
#include "genSupports.h"
#include "genSimpleFunction.h"

class GModel;

class genDomain : public genSupport
{
public :
  enum tenstype{Unknown=-1,Integer,Scalar,Vector,Tensor,CScalar,CVector,CTensor};
  std::map<std::string,int> Integers;
  std::map<std::string,double> Scalars;
  std::map<std::string,std::complex<double> > CScalars;
  std::map<std::string,std::vector<double> > Vectors;
  std::map<std::string,std::vector<std::complex<double> > > CVectors;
  std::map<std::string,genMatrix<double > > Tensors;
  std::map<std::string,genMatrix<std::complex<double> > > CTensors;
  std::map<std::string,tenstype> AllData;
  std::string type; // domain type (Elastic, etc...)
public :
  genDomain():genSupport() {}
  friend std::istream & operator>>(std::istream &is, genDomain &obj);
  friend std::ostream & operator<<(std::ostream &os, const genDomain &obj);
};

std::istream & operator>>(std::istream &is, genDomain &obj);
std::ostream & operator<<(std::ostream &os, const genDomain &obj);


class genBoundaryCondition : public genSupport
{
public :
  enum location{UNDEF=-1,ON_VERTEX,ON_EDGE,ON_FACE,ON_VOLUME};
//  enum bctype{Unknown=-1,Classic,Dirichlet,Neumann,Periodics};
//  static const char physNames[][256];//={"Displacement","Force","Potential","Charge","Temperature","ThermalFlux"};
  enum tenstype{Unknown=-1,Integer,Scalar,Vector,Tensor,CScalar,CVector,CTensor};
  std::string What; // Displacement etc...
  tenstype isWhat; // What is in the file
  std::string kind; // Dirichlet, etc...
  bool own;
  int comp1; // component on which the BC is affected
  int comp2; // eventual second component (e.g. for tensors)
  genSimpleFunction<genTensor0<double> >* fscalar;
  genSimpleFunction<genTensor0<std::complex<double> > >* fcscalar;
  genSimpleFunction<genTensor1<double> >* fvector; // bc or mapping !
  genSimpleFunction<genTensor1<std::complex<double> > >* fcvector; // bc or mapping !
  genSimpleFunction<genTensor2<double> >* ftensor;
  genSimpleFunction<genTensor2<std::complex<double> > >* fctensor;
  genBoundaryCondition* periodic; // the other entities e.g.

public :
  genBoundaryCondition() : genSupport(), What("Unknown"), isWhat(Unknown), kind(""), own(true), comp1(0), comp2(0), fscalar(0), fvector(0), ftensor(0), fcscalar(0), fcvector(0), fctensor(0), periodic(0) {}
  genBoundaryCondition(const genBoundaryCondition &other) : genSupport(other), What(other.What), isWhat(other.isWhat), kind(other.kind), own(false), comp1(other.comp1), comp2(other.comp2), fscalar(other.fscalar), fvector(other.fvector), ftensor(other.ftensor), fcscalar(other.fcscalar), fcvector(other.fcvector), fctensor(other.fctensor), periodic(other.periodic) {}
  virtual ~genBoundaryCondition();
  friend std::istream & operator>>(std::istream &is, genBoundaryCondition &obj);
  friend std::ostream & operator<<(std::ostream &os, const genBoundaryCondition &obj);
};

std::istream & operator>>(std::istream &is, genBoundaryCondition &obj);
std::ostream & operator<<(std::ostream &os, const genBoundaryCondition &obj);


class genBoundaryConditionNG : public genSupport
{
public :
  enum location{UNDEF=-1,ON_VERTEX,ON_EDGE,ON_FACE,ON_VOLUME};
//  enum bctype{Unknown=-1,Classic,Dirichlet,Neumann,Periodics};
//  static const char physNames[][256];//={"Displacement","Force","Potential","Charge","Temperature","ThermalFlux"};
  enum tenstype{Unknown=-1,Integer,Scalar,Vector,Tensor,CScalar,CVector,CTensor};
  std::string What; // Displacement etc...
  tenstype isWhat; // What is in the file
  std::string kind; // Dirichlet, etc...
  bool own;
  int comp1; // component on which the BC is affected
  int comp2; // eventual second component (e.g. for tensors)
  genSimpleFunction<genTensor<0,double> >* fscalar;
  genSimpleFunction<genTensor<0,std::complex<double> > >* fcscalar;
  genSimpleFunction<genTensor<1,double> >* fvector; // bc or mapping !
  genSimpleFunction<genTensor<1,std::complex<double> > >* fcvector; // bc or mapping !
  genSimpleFunction<genTensor<2,double> >* ftensor;
  genSimpleFunction<genTensor<2,std::complex<double> > >* fctensor;
  genBoundaryConditionNG* periodic; // the other entities e.g.

public :
  genBoundaryConditionNG() : genSupport(), What("Unknown"), isWhat(Unknown), kind(""), own(true), comp1(0), comp2(0), fscalar(0), fvector(0), ftensor(0), fcscalar(0), fcvector(0), fctensor(0), periodic(0) {}
  genBoundaryConditionNG(const genBoundaryConditionNG &other) : genSupport(other), What(other.What), isWhat(other.isWhat), kind(other.kind), own(false), comp1(other.comp1), comp2(other.comp2), fscalar(other.fscalar), fvector(other.fvector), ftensor(other.ftensor), fcscalar(other.fcscalar), fcvector(other.fcvector), fctensor(other.fctensor), periodic(other.periodic) {}
  virtual ~genBoundaryConditionNG();
  friend std::istream & operator>>(std::istream &is, genBoundaryConditionNG &obj);
  friend std::ostream & operator<<(std::ostream &os, const genBoundaryConditionNG &obj);
};

std::istream & operator>>(std::istream &is, genBoundaryConditionNG &obj);
std::ostream & operator<<(std::ostream &os, const genBoundaryConditionNG &obj);

class genDataIO
{
public:
  std::vector<genBoundaryCondition*> BCs;
  std::vector<genDomain*> Domains;
  genDomain User;
  std::string GModelBaseName;
  GModel* Model;
  int dim;
  int tag;
  int solvertype;
public:
  genDataIO() : Model(0), dim(0), tag(0), solvertype(1) {}
  virtual ~genDataIO();
  virtual void readInputFile(const std::string &fileName);
  virtual void readToken(std::istream &is, std::string &token);

  virtual void dumpContent(std::ostream &os);
};

class genDataIONG
{
public:
  std::vector<genBoundaryConditionNG*> BCs;
  std::vector<genDomain*> Domains;
  genDomain User;
  std::string GModelBaseName;
  GModel* Model;
  int dim;
  int tag;
  int solvertype;
public:
  genDataIONG() : Model(0), dim(0), tag(0), solvertype(1) {}
  virtual ~genDataIONG();
  virtual void readInputFile(const std::string &fileName);
  virtual void readToken(std::istream &is, std::string &token);

  virtual void dumpContent(std::ostream &os);
};

static int Voigt [3][3] = {{0,5,4}, {5,1,3}, {4,3,2}};

template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor4<T> &t)
{
  int i, j, k, l;
  for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l)
      t(i,j,k,l) = mv(Voigt[i][j],Voigt[k][l]);
}

template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor<4,T> &t)
{
  int i, j, k, l;
  for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k) for (l = 0; l < 3; ++l)
      t(i,j,k,l) = mv(Voigt[i][j],Voigt[k][l]);
}

template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor3<T> &t)
{
  if (mv.size1() > mv.size2())
  {
    int i, j, k;
    for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k)
      t(i,j,k) = mv(Voigt[i][j],k);
  }
  else
  {
    int i, j, k;
    for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k)
      t(i,j,k) = mv(i,Voigt[j][k]);
  }
}

template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor<3,T> &t)
{
  if (mv.size1() > mv.size2())
  {
    int i, j, k;
    for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k)
      t(i,j,k) = mv(Voigt[i][j],k);
  }
  else
  {
    int i, j, k;
    for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
    for (k = 0; k < 3; ++k)
      t(i,j,k) = mv(i,Voigt[j][k]);
  }
}


template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor2<T> &t)
{
   int i, j;
   for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
     t(i,j) = mv(i,j);
}

template<class T> void FromVoigtNotation(const genMatrix<T> &mv,genTensor<2,T> &t)
{
   int i, j;
   for (i = 0; i < 3; ++i) for (j = 0; j < 3; ++j)
     t(i,j) = mv(i,j);
}

void readVector(const std::string &string_v, std::vector<int> &v);
void readVector(const std::string &string_v, std::vector<double> &v);
void readVector(const std::string &string_v, std::vector<std::complex<double> > &v);
void readVector(const std::string &string_v, std::vector<std::string> &v);
void readArray(const std::string &string_v, double t[], int size);
void readArray(const std::string &string_v, std::complex<double> t[], int size);

void readMatrix(const std::string &string_m, genMatrix<int> &m);
void readMatrix(const std::string &string_m, genMatrix<double> &m);
void readMatrix(const std::string &string_m, genMatrix<std::complex<double> > &m);
void readMatrix(const std::string &string_m, genMatrix<std::string> &m);

void NextToken(std::istream &is, std::string &token, const std::string &next="");
void RemoveComments(std::istream &is, std::string &token);
void NextTokenWithoutComments(std::istream &is, std::string &token, const std::string &next="");

void readScalar(std::istream &is, int &s);
void readScalar(std::istream &is, double &s);
void readScalar(std::istream &is, std::complex<double> &s);
void readString(std::istream &is, std::string &s);
void readVector(std::istream &is, std::vector<int> &v);
void readVector(std::istream &is, std::vector<double> &v);
void readVector(std::istream &is, std::vector<std::complex<double> > &v);
void readVector(std::istream &is, std::vector<std::string> &v);
void readMatrix(std::istream &is, genMatrix<int> &m);
void readMatrix(std::istream &is, genMatrix<double> &m);
void readMatrix(std::istream &is, genMatrix<std::complex<double> > &m);
void readMatrix(std::istream &is, genMatrix<std::string> &m);

#endif //_GENDATAIO_H_
