/* 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_load_H
#define fesslix_flxfem_load_H

#if defined(_MSC_VER)
  #include "flxfem_export.h"
#else
  #define FLXFEM_EXPORT
#endif

#include "flxrandom.h"


/**
* @brief class dealing with element information
*/
class FLXFEM_EXPORT FlxDof {
  public:
    enum dir {	// x=0;y=1;z=2;
      x,y,z
    };
    enum dof { 
      dof_wx, dof_wy, dof_wz, dof_rx, dof_ry, dof_rz
    };
    enum dof_fixed_state {
      dof_free, dof_spring, dof_fixed, dof_predispl, dof_link
    };
    static const dof get_dof(std::string strdof, const bool errSerious = true);
    static const dof get_dof(const dir dirV, const bool isForce);
    static const dof get_dof(const tuint dirV);
    static const std::string get_dof(const dof edof);
    static const dir get_dir(const dof edof);
    static const dir get_dir(const tuint dirV);
    static const bool is_force(const dof edof);
};

class flxFEM;
class flxStiffnessMtxBase;

class FLXFEM_EXPORT FlxLoadCase {
  private:
    tuint index;
    std::string description;
    /**
    * @brief determines if the load-case is active
    */
    bool active;
    /**
    * @brief a factor with which the load case should be multiplied
    */
    tdouble factor;
  public:
    FlxLoadCase(const tuint index, const std::string& description, const bool active, const tdouble factor=1.0) : index(index), description(description), active(active), factor(factor) {}
    // NOTE this object used the copy assignment operator
    /**
    * @brief returns if the load case is active or not
    */
    const bool is_active() const { return active; }
    /**
    * @brief set the load case active or not
    */
    void set_active(const bool activeV) { active = activeV; }
    const tuint get_index() const { return index; }
    const tdouble get_factor() const { return factor; }
    /**
    * @brief log the information of the load case
    */
    void log_info(std::ostream& lout) const;
};

class FLXFEM_EXPORT FlxLoadCaseBox {
  private:
    std::map<tuint, FlxLoadCase*> box;
  public:
    ~FlxLoadCaseBox();
    void insert (const tuint index, FlxLoadCase* value, const bool silent=false);
    FlxLoadCase& get(const tuint index, const bool errSerious=true) const;
    void set_active(const std::vector<tuint> &loadcases);
    
};

class flxDOFn;
class flxVertex;
class flxNLoad;
typedef flxNLoad* flxNLoadPtr;
/**
* @brief class for nodal loads
*/
class FLXFEM_EXPORT flxNLoad {
  private:
    const FlxDof::dof dofDir;
    FlxFunction* value;
    flxNLoad* next;
    const FlxLoadCase& lc;
    
    /**
    * @brief finds the position of the nodal load within the linked list
    * @return link to the next nodal load
    */
    flxNLoad* link2list(flxNLoad* el2link);
    /**
    * @brief finds a nodal load within the list
    * @return NULL if the corresponding load is not found
    */
    flxNLoad* find(const FlxDof::dof dofDirV, const FlxLoadCase& lcV);
    /**
    * @brief assembles the force vector
    * @param dofList list of DOFs of the node ... needed for getting the corresponding DOF-index
    */
    void assembleForces(flxStiffnessMtxBase& stfmtx, flxDOFn* dofList) const;
  public:
    flxNLoad(const FlxDof::dof dofDir, FlxFunction* value, const FlxLoadCase& lc, flxNLoadPtr& start);
    ~flxNLoad();
    
    friend class flxVertex;
};

class flxDOFe;
class flxEdge;
class flxELoad;
class flxFEMrefine_1D;
typedef flxELoad* flxELoadPtr;
/**
* @brief class for edge loads
*/
class FLXFEM_EXPORT flxELoad : protected FlxBoxBaseR {
  private:
    const FlxDof::dof dofDir;
    const bool global;		// in the global coordinate system (false: local coordinate system)
    FlxFunDeg* value;
    FlxFunction* pos1;		// local coordinate of load-start [-1;1]
    FlxFunction* pos2;		// NULL in case of a point load
    flxELoad* next;
    const FlxLoadCase& lc;
    
    /**
    * @brief finds the position of the edge load within the linked list
    * @return link to the next edge load
    */
    flxELoad* link2list(flxELoad* el2link);
    /**
    * @brief helps integrate int(q*N_i)
    * @param lx1/lx2 local coordinates - start and end point of integration
    * @param elId the index of the sub-element to integrate on
    * @param pOrder the polynomial order of the ansatz functions
    * @param fv point to the force vector of the sub-element - results are stores there  (N1 PORDER_PART N2)
    */
    void integrate_help(flxEdge& edge, const tdouble &lx1, const tdouble &lx2, const tuint elId, const tdouble* meshInterval, const tuint pOrder, tdouble *fv) const;
    
    /**
    * @brief refines the edge mesh AND!!! generates the necessary edge-DOFs
    */
    void refine_mesh(flxFEMrefine_1D* mesh, flxEdge& edge, const bool *DOFnMap);
    /**
    * @brief assembles the force vector
    * @param dofList list of DOFs of the node ... needed for getting the corresponding DOF-index
    */
    void assembleForces(flxEdge& edge, const tdouble* meshInterval, const tuint meshInterval_size) const;
  public:
    flxELoad(const FlxDof::dof dofDir, const bool global, FlxFunDeg* value, FlxFunction* pos1, FlxFunction* pos2, const FlxLoadCase& lc, flxELoadPtr& start);
    ~flxELoad();
    void log_info(std::ostream& lout);
    
    friend class flxEdge;
};



#endif // fesslix_flxfem_load_H
