/* Fesslix - Stochastic Analysis
 * Copyright (C) 2010-2016 Wolfgang Betz
 *
 * Fesslix 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 3 of the License, or
 * (at your option) any later version.
 *
 * Fesslix 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 Fesslix.  If not, see <http://www.gnu.org/licenses/>. 
 */

#ifndef fesslix_flxobjfem_H
#define fesslix_flxobjfem_H

#include "flxobjects.h"
#include "flxrandomFEM.h"


FLXFEM_EXPORT flxFEM_ptr& FEMbox_get();



class FLXFEM_EXPORT flxDOFnV : public FlxDataBase {
  private:
    const FlxDof::dof dofDir;
    FlxDof::dof_fixed_state state;
    FlxFunction* state_value;
  public:
    flxDOFnV(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunction* state_value);
    ~flxDOFnV();
    void calc(flxDOFnPtr& start);
};

class FLXFEM_EXPORT flxDOFnVlist {
  private:
    std::map<FlxDof::dof, flxDOFnV*> box;
    void insert(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunction* state_value);
  public:
    flxDOFnVlist(ReadStream *reader, FlxFunctionReader *funReader, bool errSerious=true);
    ~flxDOFnVlist();
    /**
    * @brief calculates the dof-list of the node ... start must be a NULL-pointer ... and will contain the list
    */
    void calc(flxDOFnPtr& start) const;
};

class FLXFEM_EXPORT flxDOFeV : public FlxDataBase {
  private:
    const FlxDof::dof dofDir;
    FlxDof::dof_fixed_state state;
    FlxFunDeg* state_value;
    /**
    * @brief the default polynomial order of the edge to create
    */
    FlxFunction* porder;
  public:
    flxDOFeV(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunDeg* state_value, FlxFunction* porder);
    ~flxDOFeV();
    void calc(flxDOFePtr& start, const bool errSerious);
};

class FLXFEM_EXPORT flxDOFeVlist {
  private:
    std::map<FlxDof::dof, flxDOFeV*> box;
    void insert(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunDeg* state_value, FlxFunction* porder);
  public:
    flxDOFeVlist(ReadStream *reader, FlxFunctionReader *funReader, bool errSerious=true);
    ~flxDOFeVlist();
    /**
    * @brief calculates the dof-list of the edge ... start must be a NULL-pointer ... and will contain the list
    */
    void calc(flxDOFePtr& start, const bool errSerious) const;
};

class FLXFEM_EXPORT flxDOFfV : public FlxDataBase {
  private:
    const FlxDof::dof dofDir;
    const FlxDof::dof_fixed_state state;
    FlxFunDeg* state_value;
    /**
    * @brief the default polynomial order of the face to create
    */
    FlxFunction* porderLx;
    FlxFunction* porderLy;
    bool tensor;
  public:
    flxDOFfV(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunDeg* state_value, FlxFunction* porderLx, FlxFunction* porderLy, const bool tensor);
    ~flxDOFfV();
    void calc(flxDOFfPtr& start, const bool errSerious) const;
};

class FLXFEM_EXPORT flxDOFfVlist {
  private:
    std::map<FlxDof::dof, flxDOFfV*> box;
    void insert(const FlxDof::dof dofDir, const FlxDof::dof_fixed_state state, FlxFunDeg* state_value, FlxFunction* porderLx, FlxFunction* porderLy, const bool tensor);
  public:
    flxDOFfVlist(ReadStream *reader, FlxFunctionReader *funReader, bool errSerious=true);
    ~flxDOFfVlist();
    /**
    * @brief calculates the dof-list of the face ... start must be a NULL-pointer ... and will contain the list
    */
    void calc(flxDOFfPtr& start, const bool errSerious) const;
};

// -------------------------- OBJECTS ----------------------------------------------------------------------


/**
* @brief object class: define a node
*
* node index x y z fix enumFix [value] ... spring enumFix value ...
*/
class FLXFEM_EXPORT FlxObjNode : public FlxObjBase {
  private:
    FlxFunction *index;
    const FlxFunPoint *p;
    const flxDOFnVlist *dofVList;
    void task();
  public:
    FlxObjNode ( const bool dolog, FlxFunction* indexV, const FlxFunPoint* pV, const flxDOFnVlist *dofVList );
    ~FlxObjNode ();
};

/**
* @brief object class: define a edge
*
* edge index Node1 Node2 fix enumFix [value] ... spring enumFix value ...
*/
class FLXFEM_EXPORT FlxObjEdge : public FlxObjBase {
  private:
    FlxFunction *index;
    FlxFunction *node1;
    FlxFunction *node2;
    const flxDOFeVlist *dofVList;
    const flxFEMrefine_1D* mesh;
    FlxFunction* deforder;
    const bool condenseStf;
    void task();
  public:
    FlxObjEdge ( const bool dolog, FlxFunction* indexV, FlxFunction *node1, FlxFunction *node2, const flxDOFeVlist *dofVList, const flxFEMrefine_1D* mesh, FlxFunction* deforder,  const bool condenseStf );
    ~FlxObjEdge ();
};

/**
* @brief object class: define a face
*
* edge index Node1 Node2 fix enumFix [value] ... spring enumFix value ...
*/
class FLXFEM_EXPORT FlxObjFace : public FlxObjBase {
  private:
    FlxFunction *index;
    FlxFunction *edge1;
    FlxFunction *edge2;
    FlxFunction *edge3;
    FlxFunction *edge4;
    const flxDOFfVlist *dofVList;
    FlxFunction* deforder;
    FlxFunction* refine_min;
    FlxFunction* refine_max;
    FlxFunction* geo_fun;
    FlxFunction* cellAreaPoints;
    const bool deftensor;
    const bool condenseStf;
    void task();
  public:
    FlxObjFace ( const bool dolog, FlxFunction* indexV, FlxFunction *edge1, FlxFunction *edge2, FlxFunction *edge3, FlxFunction *edge4, const flxDOFfVlist *dofVList, FlxFunction* deforder, const bool deftensor, const bool condenseStf, FlxFunction* refine_min, FlxFunction* refine_max, FlxFunction* geo_fun, FlxFunction* cellAreaPoints);
    ~FlxObjFace ();
};

/**
* @brief object class: define a box
*
* edge index Node1 Node2 fix enumFix [value] ... spring enumFix value ...
*/
class FLXFEM_EXPORT FlxObjBox : public FlxObjBase {
  private:
    FlxFunction *index;
    FlxFunction *face1;
    FlxFunction *face2;
    FlxFunction *face3;
    FlxFunction *face4;
    FlxFunction *face5;
    FlxFunction *face6;
    void task();
  public:
    FlxObjBox ( const bool dolog, FlxFunction* indexV, FlxFunction *face1, FlxFunction *face2, FlxFunction *face3, FlxFunction *face4, FlxFunction *face5, FlxFunction *face6 );
    ~FlxObjBox ();
};

/**
* @brief object class: define an isotropic material
*
* material INDEX p1 VALUE p2 VALUE
*/
class FLXFEM_EXPORT FlxObjIsoMaterial : public FlxObjBase {
  private:
    FlxFunction* index;
    flxMaterial *mat;
    void task();
  public:
    FlxObjIsoMaterial ( bool dolog, FlxFunction* indexV, flxMaterial *mat ): FlxObjBase(dolog), index(indexV), mat(mat) {};
    ~FlxObjIsoMaterial ();
};

class FlxCrossSec_Generator_base;
/**
* @brief object class: define a cross section
*
* crosssec INDEX Manual A A Iy IY Iz IZ
*/
class FLXFEM_EXPORT FlxObjCrossSec : public FlxObjBase {
  private:
    FlxFunction* index;
    FlxCrossSec_Generator_base* cSG;
    void task();
  public:
    FlxObjCrossSec( bool dolog, FlxFunction* indexV, FlxCrossSec_Generator_base *cSG ): FlxObjBase(dolog), index(indexV), cSG(cSG) {};
    ~FlxObjCrossSec();
};

/**
* @brief object class: define a nodal load
*
* loadcase INDEX { factor= ; descr= ;};
*/
class FLXFEM_EXPORT FlxObjLoadCase : public FlxObjBase {
  private:
    FlxFunction* index;
    FlxFunction* factor;
    FlxString* descr;
    void task();
  public:
    FlxObjLoadCase( bool dolog, FlxFunction* indexV, FlxFunction* factorV, FlxString* descrV ): FlxObjBase(dolog), index(indexV), factor(factorV),descr(descrV) {};
    ~FlxObjLoadCase();
};

/**
* @brief object class: define a nodal load
*
* nload INDEX DOF VALUE
*/
class FLXFEM_EXPORT FlxObjNLoad : public FlxObjBase {
  private:
    FlxFunction* index;
    const FlxDof::dof dofV;
    FlxFunction* value;
    FlxFunction* loadcase;
    const bool evalVal;
    const bool replace;
    void task();
  public:
    FlxObjNLoad( const bool dolog, FlxFunction* indexV, const FlxDof::dof dofV, FlxFunction* valueV, const bool evalVal, const bool replaceV, FlxFunction* loadcaseV ): FlxObjBase(dolog), index(indexV), dofV(dofV),value(valueV),loadcase(loadcaseV),evalVal(evalVal),replace(replaceV) {};
    ~FlxObjNLoad();
};

/**
* @brief object class: define an element load
*
* eload ...
*/
class FLXFEM_EXPORT FlxObjELoad : public FlxObjBase {
  private:
    FlxFunction* edgeIdx;
    const bool global;
    const FlxDof::dof dofV;
    FlxFunDeg* value;
    FlxFunction* pos1;		// local coordinate of load-start [-1;1]
    FlxFunction* pos2;		// NULL in case of a point load
    FlxFunction* LCfun;

    void task();
  public:
    FlxObjELoad( bool dolog, FlxFunction* edgeIdx, const bool global, const FlxDof::dof dofV, FlxFunDeg* value, FlxFunction* pos1, FlxFunction* pos2, FlxFunction* LCfun);
    ~FlxObjELoad();
};

/**
* @brief object class: define a truss element
*
* truss INDEX EDGE_IDX material MATERIAL crosssec CROSSSEC;
*/
class FLXFEM_EXPORT FlxObjElTruss : public FlxObjBase {
  protected:
    FlxFunction* index;
    FlxFunction* edge_index;
    FlxFunction* material;
    FlxFunction* crossSec;
    bool allowFastIntegration;
    void task();
  public:
    FlxObjElTruss( const bool dolog, FlxFunction* index, FlxFunction* edge_index, FlxFunction* material, FlxFunction* crossSec, const bool allowFastIntegration);
    virtual ~FlxObjElTruss();
};

/**
* @brief object class: define a beam element
*
* elbeam INDEX N1 N2 material MATERIAL crosssec CROSSSEC;
*/
class FLXFEM_EXPORT FlxObjElBeam : public FlxObjBase {
  private:
    FlxFunction* index;
    FlxFunction* edge_index;
    FlxFunction* material;
    FlxFunction* crossSec;
    void task();
  public:
    FlxObjElBeam( const bool dolog, FlxFunction* index, FlxFunction* edge_index, FlxFunction* material, FlxFunction* crossSec);
    virtual ~FlxObjElBeam();
};

/**
* @brief object class: define a plane stress/strain element
*
* elplanestr INDEX N1 N2 N3 N4 material MATERIAL planestress BOOL;
*/
class FLXFEM_EXPORT FlxObjElPlaneStr : public FlxObjBase {
  private:
    FlxFunction* index;
    FlxFunction* face_index;
    FlxFunction* material;   
    FlxFunDeg* t;
    bool planeStress;
    void task();
  public:
    FlxObjElPlaneStr( bool dolog, FlxFunction* index, FlxFunction* face_index, FlxFunction* material, FlxFunDeg* t, bool planeStress);
    ~FlxObjElPlaneStr();
};

/**
* @brief object class: import geometry of plane stress/strain elements from file (h-FEM)
*
*/
class FLXFEM_EXPORT FlxObjImportData_ElPlaneStr : public FlxObjBase {
  private:
    FlxString* filename;
    FlxFunction* material;   
    FlxFunDeg* t;
    FlxFunction* lcfun;
    bool planeStress;
    FlxFunction* RFindex;
    FlxKLelementProp_base* KLelProp;
    void task();
  public:
    FlxObjImportData_ElPlaneStr( bool dolog, FlxString* filename, FlxFunction* material, FlxFunDeg* t, bool planeStress, FlxFunction* lcfun, FlxFunction* RFindex, FlxKLelementProp_base* KLelProp);
    ~FlxObjImportData_ElPlaneStr();
};

/**
* @brief object class: import geometry for random fields from a SOFiSTiK-mesh
*
*/
class FLXFEM_EXPORT FlxObjImportData_ElPlaneStr_SOFiSTiK : public FlxObjBase {
  private:
    FlxString* filename;
    FlxFunction* RFindex;
    FlxKLelementProp_base* KLelProp;
    void task();
  public:
    FlxObjImportData_ElPlaneStr_SOFiSTiK( bool dolog, FlxString* filename, FlxFunction* RFindex, FlxKLelementProp_base* KLelProp) : FlxObjBase(dolog), filename(filename), RFindex(RFindex), KLelProp(KLelProp) {}
    ~FlxObjImportData_ElPlaneStr_SOFiSTiK();
};

/**
* @brief object class: create new FEM-object
*/
class FLXFEM_EXPORT FlxObjControlFEM_new : public FlxObjOutputBase {
  protected:
    virtual void task();
  public:
    FlxObjControlFEM_new ( bool dolog, std::string ostreamV, bool verbose ) : FlxObjOutputBase(dolog,ostreamV,verbose) {}
};

/**
* @brief object class: assemble DOF
*/
class FLXFEM_EXPORT FlxObjControlFEM_assembleDOF : public FlxObjOutputBase {
  protected:
    virtual void task();
  public:
    FlxObjControlFEM_assembleDOF ( bool dolog, std::string ostreamV, bool verbose );
    ~FlxObjControlFEM_assembleDOF() {}
};

/**
* @brief object class: assemble Stiffness Matrix
*/
class FLXFEM_EXPORT FlxObjControlFEM_assembleStf : public FlxObjOutputBase {
  protected:
    bool printmtx;
    virtual void task();
  public:
    FlxObjControlFEM_assembleStf ( bool dolog, std::string ostreamV, bool verbose, bool printmtx ) : FlxObjOutputBase(dolog,ostreamV,verbose),printmtx(printmtx) {}
};

/**
* @brief object class: assemble Force Vector
*/
class FLXFEM_EXPORT FlxObjControlFEM_assembleForc : public FlxObjOutputBase {
  protected:
    std::vector<FlxFunction*> loadcases;
    bool printforceVec;
    virtual void task();
  public:
    FlxObjControlFEM_assembleForc ( bool dolog, std::string ostreamV, bool verbose, std::vector<FlxFunction*> loadcasesV, bool printforceVec ) : FlxObjOutputBase(dolog,ostreamV,verbose), loadcases(loadcasesV), printforceVec(printforceVec) {}
    ~FlxObjControlFEM_assembleForc();
};

/**
* @brief object class: solve the system
*/
class FLXFEM_EXPORT FlxObjControlFEM_solve : public FlxObjOutputBase {
  protected:
    FlxFunction* iter;
    FlxFunction* eps;
    FlxFunction* pcn;
    bool startZero;
    bool printsol;
    bool printmtx;
    virtual void task();
  public:
    FlxObjControlFEM_solve ( const bool dolog,FlxFunction* iter, FlxFunction* eps, FlxFunction* pcn, std::string ostreamV, const bool verbose, const bool printsol, const bool printmtx, const bool startZero ) : FlxObjOutputBase(dolog,ostreamV,verbose),iter(iter),eps(eps),pcn(pcn),startZero(startZero),printsol(printsol),printmtx(printmtx) {}
    virtual ~FlxObjControlFEM_solve();
};

/**
* @brief object class: update the element displacement vectors
*/
class FLXFEM_EXPORT FlxObjControlFEM_updateDispl : public FlxObjBase {
  protected:
    virtual void task();
  public:
    FlxObjControlFEM_updateDispl ( bool dolog ) : FlxObjBase(dolog) {}
};

/**
* @brief object class: print nodes
*/
class FLXFEM_EXPORT FlxObjControlFEM_printNodes : public FlxObjOutputBase {
  protected:
    bool printsol;
    virtual void task();
  public:
    FlxObjControlFEM_printNodes ( const bool dolog, std::string ostreamV, const bool printsol ) : FlxObjOutputBase(dolog,ostreamV), printsol(printsol) {}
};


class FLXFEM_EXPORT FlxObjElPlot : public FlxObjOutputBase {
  protected:
    const std::vector<FlxElementInfo::elInfo> V;
    FlxMtxConstFun* ppdim;
    FlxMtxConstFun* elfun;
    virtual void task();
  public:
    FlxObjElPlot(bool dolog,const std::vector<FlxElementInfo::elInfo>& V, FlxMtxConstFun* ppdim, std::string ostreamV, FlxMtxConstFun* elfun, const int prec, const int fixW): FlxObjOutputBase(dolog,ostreamV,false,false,prec,fixW), V(V), ppdim(ppdim), elfun(elfun) {}
    ~FlxObjElPlot();
};

// -------------------------- READERS ----------------------------------------------------------------------

class FLXFEM_EXPORT FlxObjReadFEMbase : public FlxObjReadBase {
  protected:
    flxFun_DegreeDetect* get_optPara_DegreeDetect(const std::string& str);
    flxFEMrefine_1D* get_optPara_Refine_1D(const std::string& str);
    
    FlxObjReadFEMbase() : FlxObjReadBase(true) {}
    virtual ~FlxObjReadFEMbase () {};
};

/**
* @brief object read class: for FlxObjNode
*/
class FLXFEM_EXPORT FlxObjReadNode : public FlxObjReadFEMbase {
  public:
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjEdge
*/
class FLXFEM_EXPORT FlxObjReadEdge : public FlxObjReadFEMbase {
  public:
    FlxObjReadEdge();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjFace
*/
class FLXFEM_EXPORT FlxObjReadFace : public FlxObjReadFEMbase {
  public:
    FlxObjReadFace();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjBox
*/
class FLXFEM_EXPORT FlxObjReadGeoBox : public FlxObjReadFEMbase {
  public:
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjIsoMaterial
*/
class FLXFEM_EXPORT FlxObjReadIsoMaterial : public FlxObjReadFEMbase {
  protected:
    virtual FlxFunction* read_matprop(char& c, bool errSerious = false);
  public:
    FlxObjReadIsoMaterial();
    virtual ~FlxObjReadIsoMaterial() {};
    virtual FlxObjBase* read ();
};

class FLXFEM_EXPORT FlxCrossSec_Generator_base : public FlxReaderBase2 {
  public:
    virtual ~FlxCrossSec_Generator_base() {};
    /**
    * @brief create an instance of a crosssection
    */
    virtual flxCrossSec* generate_CrossSec() = 0;
    // Types of Crosssections
      static flxCrossSec::cstype get_cst(std::string strcst, bool errSerious = true);
      static std::string get_cst(flxCrossSec::cstype cst);
    /**
    * @brief create an instance of a crosssection generator
    */
    static FlxCrossSec_Generator_base* createCS(flxCrossSec::cstype cst);   
};

class FLXFEM_EXPORT FlxCrossSec_Generator_Manual : public FlxCrossSec_Generator_base {
  private:
    FlxFunDeg* A;
    FlxFunDeg* Iy;
    FlxFunDeg* Iz;
    FlxFunDeg* It;
  public:
    FlxCrossSec_Generator_Manual();
    virtual ~FlxCrossSec_Generator_Manual() { delete A; delete Iy; delete Iz; delete It;}
    flxCrossSec* generate_CrossSec();
};

/**
* @brief object read class: for FlxObjCrossSec
*/
class FLXFEM_EXPORT FlxObjReadCrossSec : public FlxObjReadFEMbase {
  public:
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjCrossSec
*/
class FLXFEM_EXPORT FlxObjReadLoadCase : public FlxObjReadFEMbase {
  public:
    FlxObjReadLoadCase();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjCrossSec
*/
class FLXFEM_EXPORT FlxObjReadNLoad : public FlxObjReadFEMbase {
  public:
    FlxObjReadNLoad();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjCrossSec
*/
class FLXFEM_EXPORT FlxObjReadELoad : public FlxObjReadFEMbase {
  public:
    FlxObjReadELoad();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjElTruss
*/
class FLXFEM_EXPORT FlxObjReadElTruss : public FlxObjReadFEMbase {
  protected:
    
  public:
    FlxObjReadElTruss();
    virtual ~FlxObjReadElTruss() {};
    FlxObjBase* read();
};

/**
* @brief object read class: for FlxObjElBeam
*/
class FLXFEM_EXPORT FlxObjReadElBeam : public FlxObjReadFEMbase {
  public:
    FlxObjReadElBeam();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjElPlaneStr
*/
class FLXFEM_EXPORT FlxObjReadElPlaneStr : public FlxObjReadFEMbase {
  public:
    FlxObjReadElPlaneStr();
    FlxObjBase* read ();
};

/**
* @brief object read class: for FlxObjControlFEM
*/
class FLXFEM_EXPORT FlxObjReadControlFEM : public FlxObjReadOutputBase {
  protected:
    FlxFunction* get_dfun(std::string dstr);
    bool get_printsol();
    bool get_printmtx();
    bool get_startZero();
    virtual FlxObjBase* read ();
    virtual FlxObjBase* read_new(bool errSerious=false);
    virtual FlxObjBase* read_assdof(bool errSerious=false);
    virtual FlxObjBase* read_assstf(bool errSerious=false);
    virtual FlxObjBase* read_assforc(bool errSerious=false);
    virtual FlxObjBase* read_solve(bool errSerious=false);
  public:
    FlxObjReadControlFEM();
    virtual ~FlxObjReadControlFEM() {};
};


class FLXFEM_EXPORT FlxObjReadElPlot : public FlxObjReadOutputBase {
  private:
    virtual FlxObjBase* read ();
  public:
    FlxObjReadElPlot();
};

/**
* @brief object read class: for FlxObjElPlaneStr
*/
class FLXFEM_EXPORT FlxObjReadDataImport : public FlxObjReadFEMbase {
  public:
    FlxObjReadDataImport();
    FlxObjBase* read ();
};


// -------------------------- Functions ---------------------------------------------------------------------

class FLXFEM_EXPORT FunFEM_base : public FunBase, public FlxDataBase {
  protected:
    FunBase* node;
    FlxDof::dof dofC;
    flxDOFn* get_dof(FunBase* nodeV, FlxDof::dof dofV);
    flxDOFn* get_dof();
    std::string write_dof(FunBase* nodeV, FlxDof::dof dofV);
    std::string write_dof();
  public:
    FunFEM_base(FunBase* node,FlxDof::dof dofC):node(node),dofC(dofC){}
    virtual ~FunFEM_base();
    const bool search_circref(FlxFunction* fcr) {return (node->search_circref(fcr));};
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi);
    virtual const bool dependOn_Const(const tdouble* const thenumber);
};

/**
* @brief arithmetic read class of FunNodeU
*/
class FLXFEM_EXPORT FunReadFEM_base : public FunReadFunBase {
  protected:
    FunReadFEM_base() : FunReadFunBase(true) {};
    void read_node(FunBasePtr& node, FlxDof::dof& dofC, bool errSerious );
};

class FLXFEM_EXPORT FunNodeU : public FunFEM_base {
  public:
    FunNodeU(FunBase* node,FlxDof::dof dofC):FunFEM_base(node,dofC) {};
    const tdouble calc();
    const std::string write();
    const tuint precedence() { return 0; }
};

/**
* @brief arithmetic read class of FunNodeU
*/
class FLXFEM_EXPORT FunReadNodeU : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};

class FLXFEM_EXPORT FunNodeF : public FunFEM_base {
  public:
    FunNodeF(FunBase* node,FlxDof::dof dofC):FunFEM_base(node,dofC) {};
    const tdouble calc();
    const std::string write();
    const tuint precedence() { return 0; }
};

/**
* @brief arithmetic read class of FunNodeF
*/
class FLXFEM_EXPORT FunReadNodeF : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};


class FLXFEM_EXPORT FunFEMelInfo : public FunBase, public FlxDataBase {
  protected:
    FunBase* elF;
    FlxElementInfo::elInfo elI;
    FunBase* lxF;
    FunBase* lyF;
    FunBase* lzF;
  public:
    FunFEMelInfo(FunBase* elF, FlxElementInfo::elInfo elI, FunBase* lxF, FunBase* lyF, FunBase* lzF) : elF(elF), elI(elI), lxF(lxF), lyF(lyF), lzF(lzF) {}
    ~FunFEMelInfo();
    const tdouble calc();
    const std::string write();
    const tuint precedence() { return 0; }
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi);
    const bool dependOn_Const(const tdouble* const thenumber);
};

/**
* @brief arithmetic read class of FunFEMelInfo
*/
class FLXFEM_EXPORT FunReadFEMelInfo : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};

class FLXFEM_EXPORT FunGeoCalc : public FunBase, public FlxDataBase {
  protected:
    const flxDomain_base::geoel_type typeEL;	// type of the element (edge,face,box)
    FunBase* elindex;			// index of the element
    FunBase* fun;
    FunBase* lxF;
    FunBase* lyF;
    FunBase* lzF;
  public:
    FunGeoCalc(const flxDomain_base::geoel_type typeEL, FunBase* elindex, FunBase* fun, FunBase* lxF, FunBase* lyF, FunBase* lzF) : typeEL(typeEL), elindex(elindex), fun(fun), lxF(lxF), lyF(lyF), lzF(lzF) {}
    ~FunGeoCalc();
    const tdouble calc();
    const std::string write();
    const tuint precedence() { return 0; }
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi);
    const bool dependOn_Const(const tdouble* const thenumber);
};

class FLXFEM_EXPORT FunReadGeoCalc : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};

class FLXFEM_EXPORT FunGeoInteg : public FunBase, public FlxDataBase {
  protected:
    const flxDomain_base::geoel_type typeEL;	// type of the element (edge,face,box)
    FunBase* elindex;			// index of the element
    FunBase* fun;
    FunBase* GPxF;
    FunBase* GPyF;
    const bool weight;
  public:
    FunGeoInteg(const flxDomain_base::geoel_type typeEL, FunBase* elindex, FunBase* fun, const bool weight, FunBase* GPx, FunBase* GPy) : typeEL(typeEL), elindex(elindex), fun(fun), GPxF(GPx), GPyF(GPy), weight(weight) {}
    ~FunGeoInteg();
    const tdouble calc();
    const std::string write();
    const tuint precedence() { return 0; }
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi);
    const bool dependOn_Const(const tdouble* const thenumber);
};

class FLXFEM_EXPORT FunReadGeoInteg : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};

class FLXFEM_EXPORT FunGeoTimer : public FunGeoCalc {
  protected:
    FunBase* NumberRun;
  public:
    FunGeoTimer(const flxDomain_base::geoel_type typeEL, FunBase* elindex, FunBase* fun, FunBase* lxF, FunBase* lyF, FunBase* lzF,FunBase* NumberRun) : FunGeoCalc(typeEL,elindex,fun,lxF,lyF,lzF), NumberRun(NumberRun) {}
    ~FunGeoTimer();
    const tdouble calc();
    const std::string write();
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi);
//     const bool dependOn_Const(const tdouble* const thenumber);
};

class FLXFEM_EXPORT FunReadGeoTimer : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious );
};

/**
* @brief arithmetic class:
*/
class FLXFEM_EXPORT FunHLegendrePoly : public FunBaseFun_multPara {
  public:
    FunHLegendrePoly (std::vector<FunBase*> *ParaListV) : FunBaseFun_multPara(ParaListV) {};
    const tdouble calc();
    const std::string write_v() { return "hlegendrepoly";}
};


class FLXFEM_EXPORT FunReadFunHLegendrePoly : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious ) { return new FunHLegendrePoly( read_parameters(2,errSerious) ); }
};

/**
* @brief arithmetic class:
*/
class FLXFEM_EXPORT FunHGegenbauerPoly : public FunBaseFun_multPara {
  public:
    FunHGegenbauerPoly (std::vector<FunBase*> *ParaListV) : FunBaseFun_multPara(ParaListV) {};
    const tdouble calc();
    const std::string write_v() { return "hgegenbauerpoly";}
};

class FLXFEM_EXPORT FunReadFunHGegenbauerPoly : public FunReadFEM_base {
  public:
    FunBase* read ( bool errSerious ) { return new FunHGegenbauerPoly( read_parameters(2,errSerious) ); }
};


// --------------------------------------------------------------------------------------------------------


class FLXFEM_EXPORT FlxOptionalParaFunDeg : public FlxOptionalParaBase {
  private:
    /**
    * @brief The default value; this value will be deleted by the destructor
    */
    FlxFunDeg* defv;
    /**
    * @brief The value; this value will be deleted by the destructor
    */
    FlxFunDeg *value;
    /**
    * @brief Set a new function;
    */
    void set(void* valueP);
  public:
    FlxOptionalParaFunDeg(FlxFunDeg* defV, std::string pName) : FlxOptionalParaBase(pName), defv(defV), value(NULL) {}
    FlxOptionalParaFunDeg(tdouble defV, std::string pName);
    ~FlxOptionalParaFunDeg();
    /**
    * @brief Read the function - and allocate memory;
    */
    void* read_value(bool errSerious) { return ( new FlxFunDeg(reader,funReader,errSerious)); }
    /**
    * @brief Return the function - the function is copied and has to be deleted by some other function;
    */
    void* get();
    /**
    * @brief Set a new default function;
    */
    void set_default(void* defV);
    /** 
    * @brief Delete valueP (used by flxObjDefault);
    */
    void free_value(void* valueP);
};

class FLXFEM_EXPORT FlxOptionalParaFunDegDetect : public FlxOptionalParaBase {
  private:
    /**
    * @brief The default value; this value will be deleted by the destructor
    */
    flxFun_DegreeDetect* defv;
    /**
    * @brief The value; this value will be deleted by the destructor
    */
    flxFun_DegreeDetect *value;
    /**
    * @brief Set a new detector;
    */
    void set(void* valueP);
  public:
    FlxOptionalParaFunDegDetect(flxFun_DegreeDetect* defV, std::string pName) : FlxOptionalParaBase(pName), defv(defV), value(NULL) {}
    ~FlxOptionalParaFunDegDetect();
    /**
    * @brief Read the detector - and allocate memory;
    */
    void* read_value(bool errSerious) { return ( new flxFun_DegreeDetect(errSerious)); }
    /**
    * @brief Return the detector - the detector is copied and has to be deleted by some other function;
    */
    void* get();
    /**
    * @brief Set a new default detector;
    */
    void set_default(void* defV);
    /** 
    * @brief Delete valueP (used by flxObjDefault);
    */
    void free_value(void* valueP);
};

class FLXFEM_EXPORT FlxOptionalParaMeshRefine_1D : public FlxOptionalParaBase {
  private:
    /**
    * @brief The default value; this value will be deleted by the destructor
    */
    flxFEMrefine_1D* defv;
    /**
    * @brief The value; this value will be deleted by the destructor
    */
    flxFEMrefine_1D *value;
    /**
    * @brief Set a new detector;
    */
    void set(void* valueP);
  public:
    FlxOptionalParaMeshRefine_1D(flxFEMrefine_1D* defV, std::string pName) : FlxOptionalParaBase(pName), defv(defV), value(NULL) {}
    ~FlxOptionalParaMeshRefine_1D();
    /**
    * @brief Read the detector - and allocate memory;
    */
    void* read_value(bool errSerious) { return ( new flxFEMrefine_1D(errSerious)); }
    /**
    * @brief Return the detector - the detector is copied and has to be deleted by some other function;
    */
    void* get();
    /**
    * @brief Set a new default detector;
    */
    void set_default(void* defV);
    /** 
    * @brief Delete valueP (used by flxObjDefault);
    */
    void free_value(void* valueP);
};


// -------------------------------------------------------------------------------------------------------

/**
* @brief object class: 
*
* print_hlegendrepoly(nth)
*/
class FLXFEM_EXPORT FlxObjPrintHLegendrePoly : public FlxObjOutputBase {
  private:
    FlxFunction *fun;
    const bool deriv;
    void task();
  public:
    FlxObjPrintHLegendrePoly ( bool dolog, FlxFunction* funV, std::string ostreamV, bool verboseV, const bool deriv ) : FlxObjOutputBase(dolog,ostreamV,verboseV), fun(funV), deriv(deriv) {}
    ~FlxObjPrintHLegendrePoly() { delete fun; }
};

/**
* @brief object read class: for FlxObjPrintHLegendrePoly
*/
class FLXFEM_EXPORT FlxObjReadPrintHLegendrePoly : public FlxObjReadOutputBase {
  public:
    FlxObjReadPrintHLegendrePoly();
    FlxObjBase* read ();
};

/**
* @brief object class: 
*
* print_hgegenbauerpoly(nth)
*/
class FLXFEM_EXPORT FlxObjPrintHGegenbauerPoly : public FlxObjOutputBase {
  private:
    FlxFunction *fun;
    void task();
  public:
    FlxObjPrintHGegenbauerPoly ( bool dolog, FlxFunction* funV, std::string ostreamV, bool verboseV ) : FlxObjOutputBase(dolog,ostreamV,verboseV), fun(funV) {}
    ~FlxObjPrintHGegenbauerPoly() { delete fun; }
};

/**
* @brief object read class: for FlxObjPrintHGegenbauerPoly
*/
class FLXFEM_EXPORT FlxObjReadPrintHGegenbauerPoly : public FlxObjReadOutputBase {
  public:
    FlxObjReadPrintHGegenbauerPoly() : FlxObjReadOutputBase(true) {};
    FlxObjBase* read ();
};


// -------------------------------------------------------------------------------------------------------------



#endif // fesslix_flxobjfem_H
