/*!\file: CreateDataSets
 * \brief general driver for creating all datasets that make a finite element iomodel
 */ 

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

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

void CreateDataSets(Elements** pelements,Nodes** pnodes, Vertices** pvertices, Materials** pmaterials, Constraints** pconstraints, Loads** ploads,Parameters** pparameters,IoModel* iomodel,char* rootpath,const int solution_type,const int analysis_type,const int nummodels,int analysis_counter){

	bool        continuous = true;
	Elements   *elements   = NULL;
	Materials  *materials  = NULL;
	Parameters *parameters = NULL;

	/*Create elements, vertices and materials, independent of analysis_type: */
	CreateElementsVerticesAndMaterials(pelements, pvertices, pmaterials, iomodel,nummodels);

	/*Recover elements and materials, for future update: */
	elements=*pelements;
	materials=*pmaterials;

	/*Now, branch onto analysis dependent model generation: */
	switch(analysis_type){

		#ifdef _HAVE_DIAGNOSTIC_
		case DiagnosticHorizAnalysisEnum:
			CreateNodesDiagnosticHoriz(pnodes, iomodel);
			CreateConstraintsDiagnosticHoriz(pconstraints,iomodel);
			CreateLoadsDiagnosticHoriz(ploads,iomodel);
			UpdateElementsDiagnosticHoriz(elements,iomodel,analysis_counter,analysis_type);
			break;

		case DiagnosticVertAnalysisEnum:
			CreateNodesDiagnosticVert(pnodes, iomodel);
			CreateConstraintsDiagnosticVert(pconstraints,iomodel);
			CreateLoadsDiagnosticVert(ploads,iomodel);
			UpdateElementsDiagnosticVert(elements,iomodel,analysis_counter,analysis_type);
			break;

		case DiagnosticHutterAnalysisEnum:
			CreateNodesDiagnosticHutter(pnodes, iomodel);
			CreateConstraintsDiagnosticHutter(pconstraints,iomodel);
			CreateLoadsDiagnosticHutter(ploads,iomodel);
			UpdateElementsDiagnosticHutter(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		#ifdef _HAVE_HYDROLOGY_
		case HydrologyAnalysisEnum:
			CreateNodesHydrology(pnodes, iomodel);
			CreateConstraintsHydrology(pconstraints,iomodel);
			CreateLoadsHydrology(ploads,iomodel);
			UpdateElementsHydrology(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		#ifdef _HAVE_THERMAL_
		case ThermalAnalysisEnum:
			CreateNodesThermal(pnodes, iomodel);
			CreateConstraintsThermal(pconstraints,iomodel);
			CreateLoadsThermal(ploads,iomodel);
			UpdateElementsThermal(elements,iomodel,analysis_counter,analysis_type);
			break;

		case EnthalpyAnalysisEnum:
			CreateNodesEnthalpy(pnodes, iomodel);
			CreateConstraintsEnthalpy(pconstraints,iomodel);
			CreateLoadsEnthalpy(ploads,iomodel);
			UpdateElementsEnthalpy(elements,iomodel,analysis_counter,analysis_type);
			break;

		case MeltingAnalysisEnum:
			CreateNodesMelting(pnodes, iomodel);
			CreateConstraintsMelting(pconstraints,iomodel);
			CreateLoadsMelting(ploads,iomodel);
			UpdateElementsMelting(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		#ifdef _HAVE_BALANCED_
		case BalancethicknessAnalysisEnum:
			CreateNodesBalancethickness(pnodes, iomodel);
			CreateConstraintsBalancethickness(pconstraints,iomodel);
			CreateLoadsBalancethickness(ploads,iomodel);
			UpdateElementsBalancethickness(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		#ifdef _HAVE_SLOPE_
		case BedSlopeAnalysisEnum:
			CreateNodesBedSlope(pnodes, iomodel);
			CreateConstraintsBedSlope(pconstraints,iomodel);
			CreateLoadsBedSlope(ploads,iomodel);
			UpdateElementsBedSlope(elements,iomodel,analysis_counter,analysis_type);
			break;

		case SurfaceSlopeAnalysisEnum:
			CreateNodesSurfaceSlope(pnodes, iomodel);
			CreateConstraintsSurfaceSlope(pconstraints,iomodel);
			CreateLoadsSurfaceSlope(ploads,iomodel);
			UpdateElementsSurfaceSlope(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		#ifdef _HAVE_PROGNOSTIC_
		case PrognosticAnalysisEnum:
			CreateNodesPrognostic(pnodes, iomodel);
			CreateConstraintsPrognostic(pconstraints,iomodel);
			CreateLoadsPrognostic(ploads,iomodel);
			UpdateElementsPrognostic(elements,iomodel,analysis_counter,analysis_type);
			break;
		#endif

		default:
			_error_("analysis_type: " << EnumToStringx(analysis_type) << " not supported yet!");
	}

	/*Update Elements and Materials For Control methods*/
	#ifdef _HAVE_CONTROL_
	UpdateElementsAndMaterialsControl(elements,materials,iomodel);
	#endif

	/*Generate objects that are not dependent on any analysis_type: */
	CreateParameters(pparameters,iomodel,rootpath,solution_type,analysis_type,analysis_counter);

	/*Update Elements in case we are running a transient solution: */
	#ifdef _HAVE_TRANSIENT_
	parameters=*pparameters;
	if(analysis_counter==(nummodels-1)&& solution_type==TransientSolutionEnum){
		UpdateElementsTransient(elements,parameters,iomodel,analysis_counter,analysis_type);
	}
	#endif

	/*Sort datasets: */
	SortDataSets(pelements,pnodes,pvertices, ploads, pmaterials, pconstraints, pparameters);

	/*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: */
	UpdateCounters(iomodel,pnodes,ploads,pconstraints);
}
