// GetDP - Copyright (C) 1997-2016 P. Dular and C. Geuzaine, University of Liege
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <getdp@onelab.info>.

#ifndef _DOFDATA_H_
#define _DOFDATA_H_

#include <vector>
#include "ListUtils.h"
#include "TreeUtils.h"
#include "LinAlg.h"

#define DOF_PRE  1
#define DOF_RES  2
#define DOF_TMP  3

struct Solution {
  int       TimeStep ; /* Must be first member of struct (for
			  searching purposes) */
  double    Time, TimeImag ;
  int       SolutionExist ;
  double  * TimeFunctionValues, ExplicitTimeFunctionValue ;
  gVector   x ;
} ;

struct Dof {
  int       NumType ;   /* Key 1 */
  int       Entity ;    /* Key 2 */
  int       Harmonic ;  /* Key 3 */

  int       Type ;

  /* Val must be out of the union (a member with constructor (gScalar with
     PETSc) is not allowed in a union); Val holds the init value for
     Type==Unknown, and the assigned value for Type==FixedAssociate. Val is not
     used for Type==Link. Val2 potentially holds a second init value for
     Type==Unknown */
  gScalar   Val, Val2 ;

  union {
    struct {
      int       NumDof ;  /* Equation number - 1st position */
      bool      NonLocal ; /* Set to true if equation is non-local */
    } Unknown ;
    struct {
      int       NumDof ;  /* Equation number (Associate) - 1st position */
      int       TimeFunctionIndex ;
    } FixedAssociate ;
    struct {
      int       EntityRef ;
      double    Coef, Coef2 ;
      struct Dof  * Dof ;
    } Link ;
  } Case ;
} ;

/* Dof.Type */

/* definitive in preprocessing and processing */
#define DOF_UNKNOWN              1  /* unknown */
#define DOF_FIXED                2  /* spatial fixed */
#define DOF_FIXEDWITHASSOCIATE   3  /* associate */
#define DOF_LINK                 7  /* link */
#define DOF_LINKCPLX             8  /* linkcplx */

/* definitive in a preprocessing */
#define DOF_UNKNOWN_INIT         5  /* initial condition */

/* temporary */
#define DOF_FIXED_SOLVE               4  /* waiting to be fixed by a resolution */
#define DOF_FIXEDWITHASSOCIATE_SOLVE  6  /* waiting to be fixed by a resolution */

struct CorrectionSolutions {
  List_T * Solutions ;
} ;

struct DofData {
  int       Num ;

  int       ResolutionIndex, SystemIndex ;
  int       GeoDataIndex ;
  List_T  * FunctionSpaceIndex ;
  List_T  * TimeFunctionIndex ;

  List_T  * Pulsation ;
  int       NbrHar ;
  double  * Val_Pulsation ;

  int       NbrAnyDof, NbrDof ;
  Tree_T  * DofTree ;
  List_T  * DofList ;

  int     * DummyDof ;

  char    * SolverDataFileName ;
  List_T  * Solutions ;
  struct Solution  * CurrentSolution ;
  struct Solution  * Save_CurrentSolution ;

  struct {
    int       Flag ;
    List_T  * Save_FullSolutions ;
    struct Solution  * Save_CurrentFullSolution ;
    List_T  * AllSolutions ;
  } CorrectionSolutions ;

  int       Flag_RHS ; // only assemble RHS
  int       Flag_Init[7] ;
  int       Flag_Only ;
  int       Flag_InitOnly[3] ;

  // For recalculating only the matrices that are required
  List_T   *OnlyTheseMatrices ;

  // Flag_Init[0] == 1 || Flag_Init[0] == 2
  gMatrix   A;
  gVector   b;
  gSolver   Solver;

  // Flag_Init[0] == 2
  gMatrix   Jac ;
  gVector   res, dx ;

  // Flag_Init[0] == 3 //kj+++
  gVector   df;

  // Flag_Init[1,2,3,4,5,6] == 1
  gMatrix   M1, M2, M3, M4, M5, M6;
  gVector   m1, m2, m3, m4, m5, m6;
  List_T   *m1s, *m2s, *m3s, *m4s, *m5s, *m6s;

  // Flag_Only and Flag_InitOnly[0,1,2]
  gMatrix   A1, A2, A3 ;
  gVector   b1, b2, b3 ;

  gMatrix   A_MH_moving ;
  gVector   b_MH_moving ;

  std::vector<int> NonLocalEquations;
} ;


int   fcmp_Dof(const void * a, const void * b) ;

void  Dof_InitDofData(struct DofData * DofData_P, int Num,
		      int ResolutionIndex, int SystemIndex,
		      char * Name_SolverDataFile) ;
void  Dof_FreeDofData(struct DofData * DofData_P) ;

void  Dof_SetCurrentDofData(struct DofData * DofData_P) ;

void  Dof_OpenFile(int Type, char * Name, const char * Mode) ;
void  Dof_CloseFile(int Type) ;
void  Dof_FlushFile(int Type) ;

void  Dof_WriteFilePRE0(int Num_Resolution, char * Name_Resolution, int Nbr_DofData) ;
void  Dof_ReadFilePRE0(int * Num_Resolution, int * Nbr_DofData) ;
void  Dof_WriteFilePRE(struct DofData * DofData_P) ;
void  Dof_WriteDofPRE(void * a, void * b) ;
void  Dof_ReadFilePRE(struct DofData * DofData_P) ;

void  Dof_WriteFileRES0(char * Name_File, int Format) ;
void  Dof_ReadFileRES0(void) ;
void  Dof_WriteFileRES(char * Name_File, struct DofData * DofData_P, int Format,
		       double Val_Time, double Val_TimeImag, int Val_TimeStep) ;
void  Dof_ReadFileRES(List_T * DofData_L, struct DofData * Read_DofData_P,
		      int Read_DofData, double *Time, double *TimeImag,
		      double *TimeStep) ;
void  Dof_WriteFileRES_ExtendMH(char * Name_File, struct DofData * DofData_P, int Format,
				int NbrH);
void  Dof_WriteFileRES_MHtoTime(char * Name_File, struct DofData * DofData_P,
				int Format, List_T * Time_L);
void  Dof_WriteFileRES_WithEntityNum(char * Name_File, struct DofData * DofData_P,
                                     struct GeoData * GeoData_P0, struct Group * Group_P,
                                     bool saveFixed);

void  Dof_TransferDofTreeToList(struct DofData * DofData_P) ;
void  Dof_InitDofType(struct DofData * DofData_P) ;
void  Dof_DeleteDofTree(struct DofData * DofData_P) ;

void  Dof_AddFunctionSpaceIndex(int Index_FunctionSpace) ;
void  Dof_AddTimeFunctionIndex(int Index_TimeFunction) ;
void  Dof_AddPulsation(struct DofData * DofData_P, double Val_Pulsation) ;

void  Dof_DefineAssignFixedDof(int D1, int D2, int NbrHar, double * Val,
                               int Index_TimeFunction) ;
void  Dof_DefineInitFixedDof(int D1, int D2, int NbrHar, double * Val,
                             double *Val2, bool NonLocal=false) ;
void  Dof_DefineAssignSolveDof(int D1, int D2, int NbrHar, int Index_TimeFunction) ;
void  Dof_DefineInitSolveDof(int D1, int D2, int NbrHar) ;
void  Dof_DefineLinkDof(int D1, int D2, int NbrHar, double Value[], int D2_Link) ;
void  Dof_DefineLinkCplxDof(int D1, int D2, int NbrHar, double Value[], int D2_Link) ;
void  Dof_DefineUnknownDof(int D1, int D2, int NbrHar, bool NonLocal=false) ;
void  Dof_DefineAssociateDof(int E1, int E2, int D1, int D2, int NbrHar, int init,
                             double * Val) ;
void  Dof_DefineUnknownDofFromSolveOrInitDof(struct DofData ** DofData_P) ;

void  Dof_NumberUnknownDof(void) ;

void  Dof_UpdateAssignFixedDof(int D1, int D2, int NbrHar, double *Val, double *Val2) ;
void  Dof_UpdateLinkDof(int D1, int D2, int NbrHar, double Value[], int D2_Link) ;

void  Dof_AssembleInMat(struct Dof * Equ_P, struct Dof * Dof_P, int NbrHar, double * Val,
			gMatrix * Mat, gVector * Vec, List_T *Vecs=0) ;
void  Dof_AssembleInVec(struct Dof * Equ_P, struct Dof * Dof_P, int NbrHar, double * Val,
			struct Solution * OtherSolution, gVector * Vec0, gVector * Vec) ;

void  Dof_TransferSolutionToConstraint(struct DofData * DofData_P) ;
void  Dof_TransferDof(struct DofData * DofData1_P, struct DofData ** DofData2_P);

struct  Dof * Dof_GetDofStruct(struct DofData * DofData_P, int D1, int D2, int D3) ;
gScalar Dof_GetDofValue(struct DofData * DofData_P, struct Dof * Dof_P) ;
void    Dof_GetRealDofValue(struct DofData * DofData_P, struct Dof * Dof_P, double *d) ;
void    Dof_GetComplexDofValue(struct DofData * DofData_P, struct Dof * Dof_P,
			       double *d1, double *d2) ;

void Dof_GetDummies(struct DefineSystem * DefineSystem_P, struct DofData * DofData_P) ;
void Dof_InitDofForNoDof(struct Dof * DofForNoDof, int NbrHar) ;

void Print_DofNumber(struct Dof *Dof_P) ;

#endif
