#ifndef __CMODEL_CONTMODEL_H
#define __CMODEL_CONTMODEL_H

#ifndef __CMODEL_UMDVECT3_H
#  include "umdvect3.h"
#endif

#ifndef __UNIX__
#  ifndef EXPORT
#    define EXPORT __declspec(dllexport)
#  endif
#else
#  ifndef EXPORT
#    define EXPORT 
#  endif
#endif

#define BALLs (unsigned char)100
// used for 3D
#define fb_u_dot_s     (*fb.ptu_dot_s)
#define fb_t_dot_rel   (*fb.ptt_dot_rel)
#define fb_s_force     (*fb.pts_force)
#define fb_cs_force    (*fb.ptcs_force)
#define fb_moment      (*fb.ptmoment)

struct FdBlock { // Data used to communicate between PFC and Contact Models in FD law
  // --- PFC -> Contact Models ---
  double   u_n;             // overlap +, gap -
  double   u_dot_n;         // relative velocity, normal dir.
  double   u_dot_s;         // relative velocity, shear dir. ( 2D )
  double   t_dot_rel;       // relative angular velocity ( 2D )
  UMdvect  *ptu_dot_s;      // relative velocity, shear dir. ( 3D )
  UMdvect  *ptt_dot_rel;    // relative angular velocity ( 3D )
  double   tdel;            // current time step

  // --- Contact Models -> PFC ---
  double   n_force;         // contact force, normal dir.
  double   s_force;         // contact force, shear dir. ( 2D )
  double   cs_force;        // contact force with viscous term, shear dir. ( 2D )
  double   moment;          // contact moment ( 2D )
  UMdvect  *pts_force;      // contact force, shear dir. ( 3D )
  UMdvect  *ptcs_force;     // contact force with viscous term, shear dir. ( 3D )
  UMdvect  *ptmoment;       // contact moment ( 3D )
  double   knest;           // estimated kn
  double   ksest;           // estimated ks
  double   krest;           // estimated kr, for SSB model, used FD law in Ball2D
  bool     skip;            // in case of skipping PFC FD logic after FD law of Contact Models
  bool     bfishc_brokenn;  // in case of broken contact bond (normal) invoking fishcall
  bool     bfishc_brokens;  // in case of broken contact bond (shear) invoking fishcall
  bool     bflag;           // bonding flag
  bool     broken;          // bonding flag
  bool     bSliding;        // sliding check flag
  EXPORT FdBlock(void);
};


struct PropBlock { // Data passed to Contact Models
  double        kn_c;        // normal stiffness of Default Contact model
  double        ks_c;        // shear  stiffness, DC model
  double        fric_c;      // friction coefficient, DC model
  double        n_strength;  // normal strength of contact bond, DC model
  double        s_strength;  // shear strength of contact bond, DC model
  unsigned char type_gobj2;  // object type of contact_2
  bool          bIsNear;     // control flag, IsNear() for Viscous & SSB
  double        disk_thick;  // ..... for SSB
  double        rad_gobj1;   // ..... for SSB
  double        rad_gobj2;   // ..... for SSB

  EXPORT PropBlock(void);
};


struct ModelSaveObject {
  bool          bWriting;    // true if writing to file
  unsigned long ulType;      // type value of contact model
  unsigned long ulVersion;   // contact model version number
  unsigned long ulNumDouble; // num. of double values that need to be saved
  unsigned long ulNumInt;    // num. of integral values that need to be saved
  unsigned long ulNumBool;   // num. of bool values that need to be saved
  double        *aDouble;    // array of doubles, will be uNumDouble in size
  int           *aInt;       // array of ints, will be uNumInt in size
  bool          *aBool;      // array of bools, will be uNumBool in size

  EXPORT ModelSaveObject(bool bwrite=true);
  EXPORT ~ModelSaveObject(void);
  EXPORT void Initialize(unsigned long ulNumD,
                         unsigned long ulNumI=0, unsigned long ulNumB=0);
  EXPORT void Save(unsigned long ul, double &dVal);
  EXPORT void Save(unsigned long ul, int &iVal);
  EXPORT void Save(unsigned long ul, bool &bVal);

  private:
    ModelSaveObject(const ModelSaveObject &);
    const ModelSaveObject &operator=(const ModelSaveObject &);
};


class ContactModel {
  private:
    unsigned long ulType;
  protected:
    bool     delete_flag;   // true if contact can be deleted
  public:
    // Creators
    EXPORT ContactModel(unsigned long ulTypeIn, bool bRegister=false);
    EXPORT virtual ~ContactModel(void);
    // Accessors
    EXPORT virtual const char *Name(void) const=0;
    EXPORT virtual const char **PropNames(void) const=0;
    EXPORT virtual ContactModel *Clone(PropBlock *pb=0) const=0;
    EXPORT virtual double ReturnProp(int n) const=0;
    EXPORT virtual double KsEstimate(void) const=0;
    EXPORT virtual double KnEstimate(void) const=0;
    EXPORT virtual unsigned long Version(void) const = 0;
    EXPORT unsigned long Type(void) const { return ulType; }
    EXPORT bool OKtoDelete(void) { return delete_flag; }
    EXPORT int NameToIndex(const char *strName) const;
    EXPORT const char *GetPropName(int) const;
    EXPORT virtual double &Property(int);  
    // Manipulators
    EXPORT virtual void AcceptProp(int n,double v)=0;
    EXPORT virtual const char *PreCycle(PropBlock &pb)=0;
    EXPORT virtual void FDlaw(FdBlock &fb, char cDim)=0;   
    EXPORT void SetDelete(bool d) { delete_flag = d; }
    // Save & Restore
    EXPORT virtual const char *SaveRestore(ModelSaveObject *mso);
    EXPORT virtual void remap(PropBlock &) { }
    // Static function to access all Contact Models
    EXPORT static unsigned long NumModels(void);
    EXPORT static const ContactModel *GetModel(unsigned long ulPos);
    EXPORT static const ContactModel *ContactModel::FindByType(unsigned long ulType_in);
    EXPORT static bool IsCprop(const char *strName);
    EXPORT static const char *Load(const char *strLibPathAndName,bool &);
};



#endif
