/*
 * UpdateElementsAndMaterialsControl:
 */

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

void	UpdateElementsAndMaterialsControl(Elements* elements,Materials* materials, IoModel* iomodel){

	/*Intermediary*/
	int       control;
	Element  *element = NULL;
	Material *material = NULL;
	int       num_control_type;
	bool      control_analysis;

	/*Fetch parameters: */
	iomodel->Constant(&control_analysis,InversionIscontrolEnum);
	if(control_analysis) iomodel->Constant(&num_control_type,InversionNumControlParametersEnum);

	/*Now, return if no control*/
	if (!control_analysis) return;

	/*Fetch data needed: */
	iomodel->FetchDataToInput(elements,InversionVxObsEnum,0.);
	iomodel->FetchDataToInput(elements,InversionVyObsEnum,0.); 
	iomodel->FetchDataToInput(elements,InversionThicknessObsEnum,0.);

	iomodel->FetchData(5,InversionControlParametersEnum,InversionCostFunctionsEnum,InversionCostFunctionsCoefficientsEnum,InversionMinParametersEnum,InversionMaxParametersEnum);

	for(int i=0;i<num_control_type;i++){
		control = reCast<int,IssmDouble>(iomodel->Data(InversionControlParametersEnum)[i]);
		switch(control){
			/*List of supported controls*/
			case BalancethicknessThickeningRateEnum: 
			case VxEnum:
			case VyEnum:
			case ThicknessEnum:
			case FrictionCoefficientEnum:
			case BalancethicknessNuxEnum:
			case BalancethicknessNuyEnum:
			case BalancethicknessApparentMassbalanceEnum:
				iomodel->FetchData(1,control); 
				break;

			/*Special cases*/
			case MaterialsRheologyBbarEnum: iomodel->FetchData(1,MaterialsRheologyBEnum); break;
			case DamageDbarEnum:            iomodel->FetchData(1,DamageDEnum);            break;
			default:
				_error_("Control " << EnumToStringx(control) << " not implemented yet");
		}
	}

	/*Update elements: */
	int counter=0;
	for(int i=0;i<iomodel->numberofelements;i++){
		if(iomodel->my_elements[i]){
			element=(Element*)elements->GetObjectByOffset(counter);
			element->InputUpdateFromIoModel(i,iomodel); //we need i to index into elements.
			counter++;
		}
	}

	/*Free data: */
	for(int i=0;i<num_control_type;i++){
		control = reCast<int,IssmDouble>(iomodel->Data(InversionControlParametersEnum)[i]);
		switch(control){
			case MaterialsRheologyBbarEnum: iomodel->DeleteData(1,MaterialsRheologyBEnum); break;
			case DamageDbarEnum:            iomodel->DeleteData(1,DamageDEnum);            break;
			default:                        iomodel->DeleteData(1,control); 
		}
	}
	iomodel->DeleteData(5,InversionControlParametersEnum,InversionCostFunctionsCoefficientsEnum,InversionCostFunctionsEnum,InversionMinParametersEnum,InversionMaxParametersEnum);


}
