/*************************************************************************
*  Copyright (C) 2006 by Bruno Chareyre                                *
*  bruno.chareyre@hmg.inpg.fr                                            *
*                                                                        *
*  This program is free software; it is licensed under the terms of the  *
*  GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/

/*! \brief computes statistics of micro-variables assuming axi-symetry.
	
 */

#pragma once

#include "Tenseur3.h"
#include "TriaxialState.h"

namespace yade { // Cannot have #include directive inside.

namespace CGT {

#define SPHERE_DISCRETISATION 20;  //number of "teta" intervals on the unit sphere
#define LINEAR_DISCRETISATION 200; //number of intervals on segments like [UNmin,UNmax]

	// l_vertices : defines vertices for each facet
	// for facet k, the vertices indices are in column k
	const int l_vertices[4][3] = { { 1, 2, 3 }, { 0, 3, 2 }, { 3, 0, 1 }, { 2, 1, 0 } };


	class KinematicLocalisationAnalyser {
	public:
		typedef TriaxialState::Tesselation            Tesselation;
		typedef TriaxialState::RTriangulation         RTriangulation;
		typedef RTriangulation::Vertex_handle         Vertex_handle;
		typedef RTriangulation::Finite_cells_iterator Finite_cells_iterator;
		typedef RTriangulation::Cell_handle           Cell_handle;
		typedef RTriangulation::Edge_iterator         Edge_iterator;
		typedef vector<pair<Real, Real>>              RGrid1D;
		typedef vector<vector<Real>>                  RGrid2D;
		typedef vector<vector<vector<Real>>>          RGrid3D;

		KinematicLocalisationAnalyser();
		KinematicLocalisationAnalyser(const char* state_file1, bool usebz2 = true);
		KinematicLocalisationAnalyser(const char* state_file1, const char* state_file0, bool consecutive_files = true, bool usebz2 = true);
		KinematicLocalisationAnalyser(const char* base_name, int file_number0, int file_number1, bool usebz2 = true);

		~KinematicLocalisationAnalyser();

		void SetBaseFileName(string name);
		bool SetFileNumbers(int n0, int n1);
		void SetConsecutive(bool);
		void SetNO_ZERO_ID(bool);
		void SwitchStates(void);


		bool DistribsToFile(const char* output_file_name);
		///Write the averaged deformation on each grain in a file (vertices and cells lists included in the file), no need to call computeParticlesDeformation()
		bool DefToFile(const char* output_file_name = "deformations");
		bool DefToFile(const char* state_file1, const char* state_file0, const char* output_file_name = "deformation.vtk", bool usebz2 = false);
		///Save/Load states using bz2 compression
		bool           bz2;
		std::ofstream& ContactDistributionToFile(std::ofstream& output_file);
		std::ofstream& AllNeighborDistributionToFile(std::ofstream& output_file);
		std::ofstream& StrictNeighborDistributionToFile(std::ofstream& output_file);
		std::ofstream& NormalDisplacementDistributionToFile(vector<Edge_iterator>& edges, std::ofstream& output_file);

		long         Filtered_contacts(TriaxialState& state);
		long         Filtered_neighbors(TriaxialState& state);
		long         Filtered_grains(TriaxialState& state);
		Real         Filtered_volume(TriaxialState& state);
		Real         Contact_coordination(TriaxialState& state);
		Real         Neighbor_coordination(TriaxialState& state);
		Tenseur_sym3 Neighbor_fabric(TriaxialState& state);
		Tenseur_sym3 Contact_fabric(TriaxialState& state);
		Real         Contact_anisotropy(TriaxialState& state);
		Real         Neighbor_anisotropy(TriaxialState& state);

		void SetForceIncrements(void);
		void SetDisplacementIncrements(void);

		///Add surface*displacement to T
		void Grad_u(Finite_cells_iterator cell, int facet, CVector& V, Tenseur3& T);
		///compute grad_u in cell (by default, T= average grad_u in cell, if !vol_divide, T=grad_u*volume
		void Grad_u(Finite_cells_iterator cell, Tenseur3& T, bool vol_divide = true);
		/// compute grad_u for all particles, by summing grad_u of all adjaent cells using current states
		const vector<Tenseur3>& computeParticlesDeformation(void);
		/// Do everything in one step by giving some final (file1) and initial (file0) positions
		const vector<Tenseur3>& computeParticlesDeformation(const char* state_file1, const char* state_file0, bool usebz2 = true);
		///compute porisity from cumulated spheres volumes and positions of boxes
		Real computeMacroPorosity(void);

		CVector Deplacement(Cell_handle cell);                      //donne le d�placement d'un sommet de voronoi
		CVector Deplacement(Finite_cells_iterator cell, int facet); //mean displacement on a facet

		// Calcul du tenseur d'orientation des voisins
		//Tenseur_sym3 Orientation_voisins (Tesselation& Tes);

		//Set the list of edges of a given orientation (orientation defined via the z-coordinate of the normal)
		vector<Edge_iterator>& Oriented_Filtered_edges(Real Nymin, Real Nymax, vector<Edge_iterator>& filteredList);

		vector<pair<Real, Real>>& NormalDisplacementDistribution(vector<Edge_iterator>& edges, vector<pair<Real, Real>>& row);

		//member data
		int              sphere_discretisation;
		int              linear_discretisation;
		Tenseur_sym3     Delta_epsilon;
		Tenseur3         grad_u_total;
		vector<Tenseur3> ParticleDeformation;
		Tenseur3         grad_u_total_g; //grad_u averaged on extended grain cells
		TriaxialState    ts0, ts1;
		TriaxialState *  TS1, *TS0;

	private:
		int    file_number_1, file_number_0;
		string base_file_name; //Base name of state-files, complete name is (base_name+state_number).
		bool consecutive; //Are the two triax states consecutive? if "false" displacements are re-computed from the two source files; if "true" one file is enough.
		Real v_solid_total; //solid volume in the box
		Real v_total;       //volume of the box
		Real v_total_g;     //summed volumes of extended grain cells
		long n_persistent, n_new, n_lost, n_real_cells, n_real_vertices, n_fictious_vertices;
	};

} // namespace CGT

} // namespace yade
