/*!\file Node.h
 * \brief: header file for node object
 */

#ifndef _NODE_H_
#define _NODE_H_

/*Headers:*/
/*{{{*/
#include "../datastructures/datastructures.h"
#include "../shared/shared.h"
#include "./DofIndexing.h"
#include "./Update.h"
class  Inputs;
class  Hook;
class  IoModel;
class  DataSet;
class  Vertices;
template <class doubletype> class  Vector;
template <class doubletype> class  Matrix;
class ElementVector;
class ElementMatrix;
/*}}}*/

class Node: public Object{

	private:
		int approximation; //For ice flow models, we need to know what ice flow approximation is employed on this node

	public: 

		int id;    // unique arbitrary id.
		int sid;   // "serial" id (rank of this node if the dataset was serial on 1 cpu)
		int lid;   // "local"  id (rank of this node in current partition)

		bool         indexingupdate;
		DofIndexing  indexing;
		int          analysis_type;
		IssmDouble   coord_system[3][3];

		/*Node constructors, destructors*/
		Node();
		Node(int node_id,int node_sid,int node_lid,int io_index, IoModel* iomodel,int analysis_type,int approximation_in);
		~Node();

		/*Object virtual functions definitions:*/
		void    Echo();
		void    DeepEcho();
		int     Id();
		int     ObjectEnum();
		Object *copy(){_error_("Not implemented yet (similar to Elements)"); };

		/*Node numerical routines*/
		void  CreateNodalConstraints(Vector<IssmDouble>* ys);
		void  SetCurrentConfiguration(DataSet* nodes,Vertices* vertices);
		int   Sid(void); 
		int   Lid(void); 
#ifdef _HAVE_STRESSBALANCE_
		void  GetCoordinateSystem(IssmDouble* coord_system_out);
#endif
		bool  InAnalysis(int analysis_type);
		int   GetApproximation();
		int   GetNumberOfDofs(int approximation_enum,int setenum);
		int   IsClone();
		void  ApplyConstraint(int dof,IssmDouble value);
		void  RelaxConstraint(int dof);
		void  DofInSSet(int dof);
		void  DofInFSet(int dof);
		int   GetDof(int dofindex,int setenum);
		void  CreateVecSets(Vector<IssmDouble>* pv_g,Vector<IssmDouble>* pv_f,Vector<IssmDouble>* pv_s);
		void  GetDofList(int* poutdoflist,int approximation_enum,int setenum);
		void  GetLocalDofList(int* poutdoflist,int approximation_enum,int setenum);
		void  FreezeDof(int dof);
		bool  IsActive(void);
		void  Activate(void);
		void  Deactivate(void);
		void  UpdateSpcs(IssmDouble* ys);
		void  ReindexingDone(void);
		bool  RequiresDofReindexing(void);
		int   IsFloating();
		int   IsGrounded();
		void  VecMerge(Vector<IssmDouble>* ug, IssmDouble* vector_serial,int setenum);
		void  VecReduce(Vector<IssmDouble>* vector, IssmDouble* ug_serial,int setnum);
		void  DistributeDofs(int* pdofcount,int setenum);
		void  OffsetDofs(int dofcount,int setenum);
		void  ShowTrueDofs(int* truerows,int ncols,int setenum);
		void  UpdateCloneDofs(int* alltruerows,int ncols,int setenum);
		void  SetClone(int* minranks);
};

/*Methods inherent to Node: */
int* GetLocalDofList(Node** nodes,int numnodes,int setenum,int approximation);
int* GetGlobalDofList(Node** nodes,int numnodes,int setenum,int approximation);
int  GetNumberOfDofs(Node** nodes,int numnodes,int setenum,int approximation);
#ifdef _HAVE_STRESSBALANCE_
void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum);
void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array);
void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int cs_enum);
void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int* cs_array);
void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int cs_enum);
void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int* cs_array);
void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum);
void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array);
void CoordinateSystemTransform(IssmDouble** ptransform,Node** nodes,int numnodes,int* cs_array);
#endif

#endif  /* _NODE_H_ */
