#include "./GiaAnalysis.h"
#include "../toolkits/toolkits.h"
#include "../classes/classes.h"
#include "../shared/shared.h"
#include "../modules/modules.h"

/*Model processing*/
void GiaAnalysis::CreateConstraints(Constraints* constraints,IoModel* iomodel){/*{{{*/
	/*No constraints*/
}/*}}}*/
void GiaAnalysis::CreateLoads(Loads* loads, IoModel* iomodel){/*{{{*/
	/*No loads*/
}/*}}}*/
void GiaAnalysis::CreateNodes(Nodes* nodes,IoModel* iomodel,bool isamr){/*{{{*/
	::CreateNodes(nodes,iomodel,GiaAnalysisEnum,P1Enum);
}/*}}}*/
int  GiaAnalysis::DofsPerNode(int** doflist,int domaintype,int approximation){/*{{{*/
	return 1;
}/*}}}*/
void GiaAnalysis::UpdateElements(Elements* elements,Inputs* inputs,IoModel* iomodel,int analysis_counter,int analysis_type){/*{{{*/

	int giamodel=0;
	int nummodels=0;

	/*Update elements: */
	int counter=0;
	for(int i=0;i<iomodel->numberofelements;i++){
		if(iomodel->my_elements[i]){
			Element* element=(Element*)elements->GetObjectByOffset(counter);
			element->Update(inputs,i,iomodel,analysis_counter,analysis_type,P1Enum);
			counter++;
		}
	}

	/*fetch gia model type: */
	iomodel->FetchData(&giamodel,"md.gia.model");
	if(giamodel==1){ //GiaIvins
		iomodel->FetchDataToInput(inputs,elements,"md.geometry.thickness",ThicknessEnum);
		iomodel->FetchDataToInput(inputs,elements,"md.gia.mantle_viscosity",GiaMantleViscosityEnum);
		iomodel->FetchDataToInput(inputs,elements,"md.gia.lithosphere_thickness",GiaLithosphereThicknessEnum);
		iomodel->FetchDataToInput(inputs,elements,"md.mask.ice_levelset",MaskIceLevelsetEnum);
	}
	else if(giamodel==2){ //GiaCaron: not implemneted yet
	}
	else if(giamodel==3){
		/*take Ngia and Ugia from the offline models and plug into the element inputs:*/
		iomodel->FetchDataToDatasetInput(inputs,elements,"md.gia.Ngia",GiaMmeNgiaEnum);
		iomodel->FetchDataToDatasetInput(inputs,elements,"md.gia.Ugia",GiaMmeUgiaEnum);
	}
}/*}}}*/
void GiaAnalysis::UpdateParameters(Parameters* parameters,IoModel* iomodel,int solution_enum,int analysis_enum){/*{{{*/

	int                 giamodel;
	IssmDouble          modelid; 
	int                 nummodels;

	/*find gia model type: */
	parameters->AddObject(iomodel->CopyConstantObject("md.gia.model",GiaModelEnum));
	parameters->FindParam(&giamodel,GiaModelEnum);

	if(giamodel==1){ //GiaIvins
		parameters->AddObject(iomodel->CopyConstantObject("md.gia.cross_section_shape",GiaCrossSectionShapeEnum));
		parameters->AddObject(iomodel->CopyConstantObject("md.materials.lithosphere_shear_modulus",MaterialsLithosphereShearModulusEnum));
		parameters->AddObject(iomodel->CopyConstantObject("md.materials.lithosphere_density",MaterialsLithosphereDensityEnum));
		parameters->AddObject(iomodel->CopyConstantObject("md.materials.mantle_shear_modulus",MaterialsMantleShearModulusEnum));
		parameters->AddObject(iomodel->CopyConstantObject("md.materials.mantle_density",MaterialsMantleDensityEnum));
	}
	else if(giamodel==2){ //GiaCaron
	}
	else if(giamodel==3){ //GiaMme
		
		parameters->AddObject(iomodel->CopyConstantObject("md.gia.nummodels",GiaNummodelsEnum));
		parameters->FindParam(&nummodels,GiaNummodelsEnum);

		/*create double param, not int param, because Dakota will be updating it as 
		 * a double potentially: */
		iomodel->FetchData(&modelid,"md.gia.modelid");
		parameters->AddObject(new DoubleParam(GiaModelidEnum,modelid));

		/*quick checks: */
		if(nummodels<=0)_error_("giamme object in  md.gia field should contain at least 1 ensemble model!");
		if(modelid<=0 || modelid>nummodels)_error_("modelid field in giamme object of md.gia field should be between 1 and the number of ensemble runs!");
	} 


}/*}}}*/

/*Finite Element Analysis*/
void           GiaAnalysis::Core(FemModel* femmodel){/*{{{*/
	_error_("not implemented");
}/*}}}*/
ElementVector* GiaAnalysis::CreateDVector(Element* element){/*{{{*/
	/*Default, return NULL*/
	return NULL;
}/*}}}*/
ElementMatrix* GiaAnalysis::CreateJacobianMatrix(Element* element){/*{{{*/
_error_("Not implemented");
}/*}}}*/
ElementMatrix* GiaAnalysis::CreateKMatrix(Element* element){/*{{{*/
	_error_("not implemented yet");
}/*}}}*/
ElementVector* GiaAnalysis::CreatePVector(Element* element){/*{{{*/
_error_("not implemented yet");
}/*}}}*/
void           GiaAnalysis::GetSolutionFromInputs(Vector<IssmDouble>* solution,Element* element){/*{{{*/
	   _error_("not implemented yet");
}/*}}}*/
void           GiaAnalysis::GradientJ(Vector<IssmDouble>* gradient,Element*  element,int control_type,int control_interp,int control_index){/*{{{*/
	_error_("Not implemented yet");
}/*}}}*/
void           GiaAnalysis::InputUpdateFromSolution(IssmDouble* solution,Element* element){/*{{{*/
	_error_("not implemented yet");
}/*}}}*/
void           GiaAnalysis::UpdateConstraints(FemModel* femmodel){/*{{{*/
	/*Default, do nothing*/
	return;
}/*}}}*/
