/*!\file: CreateParametersOutputDefinitions.cpp
 * \brief driver for creating output definitions dataset, and including it into the parameters dataset
 */ 

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

void CreateOutputDefinitions(Elements* elements, Parameters* parameters,IoModel* iomodel){

	int i,j;
	
	DataSet*     output_definitions      = NULL;
	int*         output_definition_enums = NULL;
	int          num_output_definitions;

	/*Create output_definitions dataset: */
	output_definitions=new DataSet();
	
	iomodel->FetchData(&output_definition_enums,&num_output_definitions,NULL,OutputdefinitionListEnum);
	if(num_output_definitions){
		for (i=0;i<num_output_definitions;i++){

			if (output_definition_enums[i]==MassfluxatgateEnum){

				/*Deal with mass flux gates:{{{ */
				
				/*massfluxatgate variables: */
				int          numgates;
				char       **gatenames               = NULL;
				IssmDouble **gatesegments            = NULL;
				int         *gatesegments_M          = NULL;


				/*Fetch segments and names: */
				iomodel->FetchMultipleData(&gatenames,&numgates,MassfluxatgateNameEnum);
				iomodel->FetchMultipleData(&gatesegments,&gatesegments_M,NULL,&numgates,MassfluxatgateSegmentsEnum);

				for(j=0;j<numgates;j++){
					output_definitions->AddObject(new Massfluxatgate<IssmDouble>(gatenames[j],gatesegments_M[j],gatesegments[j]));
				}
				/*Free ressources:*/
				for(j=0;j<numgates;j++){
					char*       string = gatenames[j];    xDelete<char>(string);
					IssmDouble* gate   = gatesegments[j]; xDelete<IssmDouble>(gate);
				}
				xDelete<char*>(gatenames);
				xDelete<IssmDouble*>(gatesegments);
				xDelete<int>(gatesegments_M);
				/*}}}*/
			}
			else if (output_definition_enums[i]==MisfitEnum){
				/*Deal with misfits: {{{*/
				
				/*misfit variables: */
				int          nummisfits;
				char**       misfit_name_s             = NULL;    
				int*         misfit_model_enum_s        = NULL;
				IssmDouble** misfit_observation_s      = NULL;
				int*         misfit_observation_enum_s  = NULL;
				int*         misfit_observation_M_s    = NULL;
				int*         misfit_observation_N_s    = NULL;
				char**       misfit_timeinterpolation_s = NULL;
				IssmDouble** misfit_weights_s           = NULL;
				int*         misfit_weights_M_s    = NULL;
				int*         misfit_weights_N_s    = NULL;
				int*         misfit_weights_enum_s= NULL;

				/*Fetch name, model_enum, observation, observation_enum, etc ... (see src/m/classes/misfit.m): */
				iomodel->FetchMultipleData(&misfit_name_s,&nummisfits,MisfitNameEnum);
				iomodel->FetchMultipleData(&misfit_model_enum_s,&nummisfits,MisfitModelEnumEnum);
				iomodel->FetchMultipleData(&misfit_observation_s,&misfit_observation_M_s,&misfit_observation_N_s,&nummisfits,MisfitObservationEnum);
				iomodel->FetchMultipleData(&misfit_observation_enum_s,&nummisfits,MisfitObservationEnumEnum);
				iomodel->FetchMultipleData(&misfit_timeinterpolation_s,&nummisfits,MisfitTimeinterpolationEnum);
				iomodel->FetchMultipleData(&misfit_weights_s,&misfit_weights_M_s,&misfit_weights_N_s,&nummisfits,MisfitWeightsEnum);
				iomodel->FetchMultipleData(&misfit_weights_enum_s,&nummisfits,MisfitWeightsEnumEnum);

				for(j=0;j<nummisfits;j++){

					/*First create a misfit object for that specific enum (misfit_model_enum_s[j]):*/
					output_definitions->AddObject(new Misfit(misfit_name_s[j],misfit_model_enum_s[j],misfit_observation_enum_s[j],misfit_timeinterpolation_s[j],misfit_weights_enum_s[j]));

					/*Now, for this particular misfit object, make sure we plug into the elements: the observation, and the weights.*/
					for(i=0;i<elements->Size();i++){
						Element* element=dynamic_cast<Element*>(elements->GetObjectByOffset(i));
						element->InputCreate(misfit_observation_s[j], iomodel,misfit_observation_M_s[j],misfit_observation_N_s[j],1,misfit_observation_enum_s[j],7);
						element->InputCreate(misfit_weights_s[j], iomodel,misfit_weights_M_s[j],misfit_weights_N_s[j],1,misfit_weights_enum_s[j],7);
					}

				}

				/*Free ressources:*/
				for(j=0;j<nummisfits;j++){
					char* string=NULL;
					IssmDouble* matrix = NULL;

					string = misfit_name_s[j];    xDelete<char>(string);
					string = misfit_timeinterpolation_s[j];    xDelete<char>(string);
					matrix = misfit_observation_s[j]; xDelete<IssmDouble>(matrix);
					matrix = misfit_weights_s[j]; xDelete<IssmDouble>(matrix);
				}
				xDelete<char*>(misfit_name_s);
				xDelete<int>(misfit_model_enum_s);
				xDelete<IssmDouble*>(misfit_observation_s);
				xDelete<int>(misfit_observation_enum_s);
				xDelete<int>(misfit_observation_M_s);
				xDelete<int>(misfit_observation_N_s);
				xDelete<char*>(misfit_timeinterpolation_s);
				xDelete<IssmDouble*>(misfit_weights_s);
				xDelete<int>(misfit_weights_M_s);
				xDelete<int>(misfit_weights_N_s);
				xDelete<int>(misfit_weights_enum_s);
				/*}}}*/
			}

			else _error_("output definition enum " << output_definition_enums[i] << "not supported yet!");
		}
	}
	parameters->AddObject(new DataSetParam(OutputdefinitionEnum,output_definitions));

	/*Free ressources:*/
	delete output_definitions;
	xDelete<int>(output_definition_enums);
}
