/*!\file ModelProcessorx
 * \brief: create datasets using input binary file and a set of requested analyses
 */

#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include "../../classes/classes.h"
#include "../../shared/shared.h"
#include "./ModelProcessorx.h"

void ModelProcessorx(Elements** pelements, Nodes** pnodes, Vertices** pvertices, Materials** pmaterials, Constraints** pconstraints, Loads** ploads, Parameters** pparameters, FILE* IOMODEL,FILE* toolkitfile, char* rootpath,const int solution_enum,const int nummodels,const int* analysis_enum_list){

	int   i,analysis_enum,verbose;
	bool  isthermal,ismasstransport,isstressbalance,isgroundingline,isenthalpy,islevelset,isdamage,ishydrology;

	/*Initialize datasets*/
	Elements    *elements    = new Elements();
	Nodes       *nodes       = new Nodes();
	Vertices    *vertices    = new Vertices();
	Materials   *materials   = new Materials();
	Constraints *constraints = new Constraints();
	Loads       *loads       = new Loads();
	Parameters  *parameters  = new Parameters();

	/*Initialize IoModel from input file*/
	IoModel* iomodel = new IoModel(IOMODEL);

	/*Fetch parameters: */
	iomodel->Constant(&verbose,VerboseEnum);
	iomodel->Constant(&isthermal,TransientIsthermalEnum);
	iomodel->Constant(&isenthalpy,ThermalIsenthalpyEnum);
	iomodel->Constant(&islevelset,TransientIslevelsetEnum);
	iomodel->Constant(&ismasstransport,TransientIsmasstransportEnum);
	iomodel->Constant(&isstressbalance,TransientIsstressbalanceEnum);
	iomodel->Constant(&isgroundingline,TransientIsgroundinglineEnum);
	iomodel->Constant(&isdamage,TransientIsdamageevolutionEnum);
	iomodel->Constant(&ishydrology,TransientIshydrologyEnum);

	SetVerbosityLevel(verbose);

	if(VerboseMProcessor()) _printf0_("   starting model processor \n");

	/*Partition Elements and Nodes*/
	ElementsAndVerticesPartitioning(&iomodel->my_elements,&iomodel->my_vertices,iomodel);

	/*Create elements, vertices and materials, independent of analysis_enum: */
	CreateElementsVerticesAndMaterials(elements,vertices,materials,iomodel,nummodels);

	/*Create Parameters*/
	CreateParameters(parameters,iomodel,rootpath,toolkitfile,solution_enum);

	for(i=0;i<nummodels;i++){

		analysis_enum=analysis_enum_list[i];
		parameters->AddObject(new IntParam(AnalysisCounterEnum,i));

		/*Hack for trasient runs (FIXME: to be improved)*/
		if(solution_enum==TransientSolutionEnum && analysis_enum==ThermalAnalysisEnum  && iomodel->domaintype==Domain2DhorizontalEnum) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==MeltingAnalysisEnum  && iomodel->domaintype==Domain2DhorizontalEnum) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==EnthalpyAnalysisEnum && iomodel->domaintype==Domain2DhorizontalEnum) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==ThermalAnalysisEnum && isthermal==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==MeltingAnalysisEnum && isthermal==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==EnthalpyAnalysisEnum && isthermal==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==ThermalAnalysisEnum && isenthalpy==true) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==MeltingAnalysisEnum && isenthalpy==true) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==EnthalpyAnalysisEnum && isenthalpy==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==MasstransportAnalysisEnum && ismasstransport==false && isgroundingline==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==StressbalanceAnalysisEnum && isstressbalance==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==StressbalanceVerticalAnalysisEnum && isstressbalance==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==StressbalanceSIAAnalysisEnum && isstressbalance==false) continue;
		if(solution_enum==SteadystateSolutionEnum && analysis_enum==ThermalAnalysisEnum && isenthalpy==true) continue;
		if(solution_enum==SteadystateSolutionEnum && analysis_enum==MeltingAnalysisEnum && isenthalpy==true) continue;
		if(solution_enum==SteadystateSolutionEnum && analysis_enum==EnthalpyAnalysisEnum && isenthalpy==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==LevelsetAnalysisEnum && islevelset==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==ExtrapolationAnalysisEnum && islevelset==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==LsfReinitializationAnalysisEnum && islevelset==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==HydrologyShreveAnalysisEnum && ishydrology==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==HydrologyDCEfficientAnalysisEnum && ishydrology==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==HydrologyDCInefficientAnalysisEnum && ishydrology==false) continue;
		if(solution_enum==TransientSolutionEnum && analysis_enum==DamageEvolutionAnalysisEnum && isdamage==false) continue;

		if(VerboseMProcessor()) _printf0_("   creating datasets for analysis " << EnumToStringx(analysis_enum) << "\n");
		Analysis* analysis = EnumToAnalysis(analysis_enum);
		analysis->UpdateParameters(parameters,iomodel,solution_enum,analysis_enum);
		analysis->CreateNodes(nodes,iomodel);
		analysis->CreateConstraints(constraints,iomodel);
		analysis->CreateLoads(loads,iomodel);
		analysis->UpdateElements(elements,iomodel,i,analysis_enum);
		delete analysis;


		/* Update counters, because we have created more nodes, loads and
		 * constraints, and ids for objects created in next call to CreateDataSets
		 * will need to start at the end of the updated counters: */
		iomodel->nodecounter       = nodes->MaximumId();
		iomodel->loadcounter       = loads->NumberOfLoads();
		iomodel->constraintcounter = constraints->NumberOfConstraints();
	}

	/*Solution specific updates*/
	UpdateElementsAndMaterialsControl(elements,materials,iomodel);
	#ifdef _HAVE_DAKOTA_
	UpdateElementsAndMaterialsDakota(elements,materials,iomodel);
	#endif
	if(solution_enum==TransientSolutionEnum){
		UpdateElementsTransient(elements,parameters,iomodel,analysis_enum);
	}

	/*Output definitions dataset: */
	CreateOutputDefinitions(elements,parameters,iomodel);

	/* Sort datasets:
	 * All our datasets are already ordered by ids. Set presort flag so that
	 * later on, when sorting is requested on these datasets, it will not be
	 * redone: */
	elements->Presort();
	nodes->Presort();
	vertices->Presort();
	loads->Presort();
	materials->Presort();

	constraints->Presort();
	parameters->Presort();
	if(VerboseMProcessor()) _printf0_("   done with model processor \n");

	/*Free resources:*/
	delete iomodel;

	/*Assign output pointers:*/
	*pelements    = elements;
	*pnodes       = nodes;
	*pvertices    = vertices;
	*pmaterials   = materials;
	*pconstraints = constraints;
	*ploads       = loads;
	*pparameters  = parameters;
}
