/*! \file ModelFetchData.c
 *  \brief: wrapper to the I/O routines, for special processing of the Model structure.
 */

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

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

void  ModelFetchData(void** pdata,int* pM,int* pN,ConstDataHandle model_handle,char* data_name,char* data_type,char* sub_data_type){
	

	extern int my_rank;
	extern int num_procs;

	int string_size;
	int record_length;
	char* string=NULL;

	/*Why this routine? To make Model management simpler. FetchData is enough for regular I/O, but here, we are dealing with 
	 * I/O that can act on the model matlab array (in case we are running serially), or I/O on the binary file when running 
	 * in parallel. On a matlab model array, it is easy to find the data with name "data_name", but not in a binary file. We 
	 * are abstracting all of this with one function, operating on the DataHandle object. */

	char* repository=NULL;
	FILE* fid=NULL;
	int found=0;

	/*Ok, on the matlab side: */
	#ifdef _SERIAL_

	/*The typical model_handle is a const mxArray*, to which FetchData is applied. But here, we are dealing with a structure, the 
	 *model. Therefore, we are looking to fetch a certain field of this data. So get this field first, and then feed it to the 
	 FetchData routine. : */

	FetchData((void**)pdata,pM,pN,mxGetAssignedField(model_handle,0,data_name),data_type,sub_data_type);

	#else

	/*In parallel, we have a FetchData, which will recover data, but it will do a good job provided the FILE* descriptor 
	 * is pointing to the start of the data we want. Here, we have to go looking for the beginning of this data. */

	if(my_rank==0){
	
		/*First set FILE* position to the beginning of the file: */
		fid=(FILE*)model_handle;
		fseek(fid,0,SEEK_SET);

		/*Now march through file looking for the correct name: */
		for(;;){
			/*Read size of first string name: */
			if(fread(&string_size,sizeof(int),1,fid)==0){
				/*Ok, we have reached the end of the file. break: */
				found=0;
				break;
			}
			/*Allocate string of correct size: */
			string=(char*)xmalloc((string_size+1)*sizeof(char));
			string[string_size]='\0';

			/*Read string: */
			if(fread(string,string_size*sizeof(char),1,fid)==0){
				/*Ok, we have reached the end of the file. break: */
				found=0;
				break;
			}
			/*Is this the correct string? : */
			if (strcmp(string,data_name)==0){
				/*Ok, we have found the correct string. Pass the record length, and break: */
				fseek(fid,sizeof(int),SEEK_CUR);
				found=1;
				break;
			}
			else{
				/*This is not the correct string, read the record length, and skip it: */
				fread(&record_length,sizeof(int),1,fid);
				/*skip: */
				fseek(fid,record_length,SEEK_CUR);
			}
			/*Erase string: */
			xfree((void**)&string);
		}
	}
	MPI_Bcast(&found,1,MPI_INT,0,MPI_COMM_WORLD); 

	if(!found)throw ErrorException(__FUNCT__,exprintf("%s%s","could not find data with name",data_name));

	/*We are at the correct position! Go for it: */
	FetchData((void**)pdata,pM,pN,fid,data_type,sub_data_type);
	#endif
}
