/* 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_flxfem_base_H
#define fesslix_flxfem_base_H

#include "flxfem_geometry.h"


class FLXFEM_EXPORT flxMaterial {
  protected:
    FlxFunction *rho;
    const tuint mid;
  public:
    flxMaterial(FlxFunction *rho):rho(rho),mid(0){};
    flxMaterial(const flxMaterial& FlxM, const tuint mid);
    virtual ~flxMaterial();
    virtual const tdouble get_E() const = 0;
    virtual const tdouble get_nu() const = 0;
    virtual const tdouble get_G() const = 0;
    virtual const tdouble get_lambda() const = 0;
    virtual const tdouble get_rho() const;
    virtual const tuint get_deg_E() const = 0;
    /**
    * @brief returns elasticity Matrix for a plane stress/strain problem (3x3-Matrix)
    */
    virtual void get_ElasticityMtxPS(FlxMtxSym& Emtx,bool planeStress) const = 0;
    /**
    * @brief returns elasticity Matrix for a plane stress/strain problem (for SRI_1) (2x2-Matrix)
    */
    virtual void get_ElasticityMtxPS_SRI(FlxMtxSym& Emtx,bool planeStress) const = 0;
    /**
    * @brief returns elasticity Matrix for a plane stress/strain problem (for SRI_2) (Skalar!!!)
    */
    virtual tdouble get_ElasticityMtxPS_SRI(bool planeStress) const = 0;
    /**
    * @brief copy the object - and returns a pointer to the copied object
    */
    virtual flxMaterial* copy(const tuint mid) = 0;
    /**
    * @brief log material info
    */
    virtual void log_info(std::ostream& lout) = 0;
    
    /**
    * @brief Determines if the Young's modulus depends on a specific const-variable
    */
    virtual const bool depend_E_on_Const(const tdouble* const thenumber) = 0;
};

class FLXFEM_EXPORT flxIsotropicMaterial : public flxMaterial {
  protected:
    char v1c, v2c;
    FlxFunction *v1;
    FlxFunction *v2;
    tuint deg_E;
    const tdouble check_E(tdouble E) const;
    const tdouble check_nu(tdouble nu) const;
    const tdouble check_G(tdouble G) const;
  public:
    virtual const tdouble get_E() const;
    virtual const tdouble get_nu() const;
    virtual const tdouble get_G() const;
    virtual const tdouble get_lambda() const;
    virtual const tuint get_deg_E() const { return deg_E; }
    virtual void get_ElasticityMtxPS(FlxMtxSym& Emtx,bool planeStress) const;
    void get_ElasticityMtxPS_SRI(FlxMtxSym& Emtx,bool planeStress) const;
    tdouble get_ElasticityMtxPS_SRI(bool planeStress) const;
    flxIsotropicMaterial(char v1cV, FlxFunction *v1V, char v2cV, FlxFunction *v2V, FlxFunction *rho, const tuint deg_E) : flxMaterial(rho), v1c(v1cV),v2c(v2cV),v1(v1V),v2(v2V),deg_E(deg_E) {};
    flxIsotropicMaterial(const flxIsotropicMaterial& FlxM, const tuint mid);
    virtual ~flxIsotropicMaterial();
    virtual flxIsotropicMaterial* copy(const tuint mid);
    virtual void log_info(std::ostream& lout);
    const bool depend_E_on_Const(const tdouble* const thenumber);
};

class FLXFEM_EXPORT flxMaterialList {
  private:
    std::map<tuint, flxMaterial*> box;
  public:
    void insert (tuint index, flxMaterial* mat,bool errSerious=true);
    flxMaterial* get(const tuint index, const bool errSerious);
    ~flxMaterialList(); 
};

class FLXFEM_EXPORT flxCrossSec {
  public:
    virtual ~flxCrossSec() {};
    virtual const tdouble get_Iy() const = 0;
    virtual const tdouble get_Iz() const = 0;
    virtual const tdouble get_It() const = 0;
    virtual const tdouble get_A() const = 0;
    virtual const tuint get_deg_Iy() const = 0;
    virtual const tuint get_deg_Iz() const = 0;
    virtual const tuint get_deg_It() const = 0;
    virtual const tuint get_deg_A() const = 0;
    /**
    * @brief log crossection info
    */
    virtual void log_info(std::ostream& lout) const = 0;
    
    /**
    * @brief Determines if the area of the crosssection depends on a specific const-variable
    */
    virtual const bool depend_A_on_Const(const tdouble* const thenumber) = 0;
    
    // Types of CrossSections (do NOT change the ordering)
      enum cstype { 
	csManual
      };
      
    virtual cstype get_Type() const = 0;
};

class FLXFEM_EXPORT flxCrossSecManual : public flxCrossSec {
  private:
    FlxFunDeg* A;
    FlxFunDeg* Iy;
    FlxFunDeg* Iz;
    FlxFunDeg* It;
    const tdouble check_positiv(const tdouble &value, const std::string strtype) const;
  public:
    flxCrossSecManual(FlxFunDeg* A, FlxFunDeg* Iy, FlxFunDeg* Iz, FlxFunDeg* It) : A(A),Iy(Iy),Iz(Iz),It(It) {};
    ~flxCrossSecManual();
    const tdouble get_A() const;
    const tdouble get_Iy() const;
    const tdouble get_Iz() const;
    const tdouble get_It() const;
    const tuint get_deg_Iy() const;
    const tuint get_deg_Iz() const;
    const tuint get_deg_It() const;
    const tuint get_deg_A() const;
    void log_info(std::ostream& lout) const;
    
    const bool depend_A_on_Const(const tdouble* const thenumber);
    
    cstype get_Type() const {return csManual;}
};

/**
* @brief stores all defined crosssections
*/
class FLXFEM_EXPORT flxCrossSecList {
  private:
    std::map<tuint, flxCrossSec*> box;
  public:
    void insert (const tuint index, flxCrossSec* cS,const bool errSerious=true);
    flxCrossSec* get(const tuint index, const bool errSerious);
    ~flxCrossSecList(); 
};


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

class FLXFEM_EXPORT FunFEMmaterial_E : public FunBase {
  protected:
    flxMaterial* mat;
  public:
    FunFEMmaterial_E(flxMaterial* mat) : mat(mat) {}
    const tdouble calc() { return mat->get_E(); }
    const std::string write();
    const tuint precedence() { return 0; }
    const bool dependOn_Const(const tdouble* const thenumber);
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi) { return false; }
};

class FLXFEM_EXPORT FunFEMcrosssec_A : public FunBase {
  protected:
    flxCrossSec* cs;
  public:
    FunFEMcrosssec_A(flxCrossSec* cs) : cs(cs) {}
    const tdouble calc() { return cs->get_A(); }
    const std::string write();
    const tuint precedence() { return 0; }
    const bool dependOn_Const(const tdouble* const thenumber);
    const bool search_circref(FlxFunction* fcr);
    const bool optimize(FunBasePtr& optf, const Fun_OptimizeInfo &foi) { return false; }
};


#endif // fesslix_flxfem_base_H
