#include <stdio.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include "boosterskel.h"

#define USAGE "Usage: don't."
#include <inttypes.h>
#include <stdlib.h>
#include <hdf5.h>
#define N_COLS 1
#define CHUNK_SIZE 500
typedef struct InRec_s {
  float stellar_params_cov_triu[21];
  int64_t gdr3_source_id;
} InRec;
#define HDFGUARD(x) if ((x)<0) abort();
#define QUERY_N_PARS 2

enum outputFields {
	fi_source_id,    /* Source Id, bigint */
	fi_triu,         /* Cov, real[21] */
};

Field *getTuple(InRec *data, int rowIndex)
{
	static unsigned char buf[20+21*(4+sizeof(float))];

	static Field vals[QUERY_N_PARS];
	/* Gaia DR3 unique source identifier. You can match this against gaia.dr3lite on this TAP service. (bigint) */
	MAKE_BIGINT(fi_source_id, ((uint64_t)(data->gdr3_source_id)));
	/* Covariance matrix of the stellar parameters from \schema.main. The variables are, in sequence: T_eff, [Fe/H], logg, ξ, E, and parallax. (real[21]) */
	size_t tmplen = packArray(buf, (unsigned char*)data->stellar_params_cov_triu, 21, 700, sizeof(float), 1);
	MAKE_ARRAY(fi_triu, buf, tmplen);
	return vals;
}

/* Common main header */
void createDumpfile(int argc, char **argv)
{
	FILE *destination=stdout;
	char inputLine[INPUT_LINE_MAX];
	int recCount = 0;
/* /Common main header */

	hid_t input_id;	
	hid_t main_id;

	hid_t datasets[N_COLS];
	hid_t colspace;
	hid_t arr_colspace;
  hsize_t arr_chunk_size[2] = {CHUNK_SIZE, 21};
  hsize_t arr_offsets[2] = {0, 0};
	hid_t arr_memspace = H5Screate_simple(2, arr_chunk_size, NULL);

	size_t nrecs;
	int rank;
	hsize_t dims[1], offsets[1];
	hsize_t null_offset[1] = {0};
	hsize_t arr_null_offsets[2] = {0,0};
	hsize_t chunk_size[1] = {CHUNK_SIZE};
	hid_t memspace = H5Screate_simple(1, chunk_size, NULL);
	size_t index_in_chunk = CHUNK_SIZE;
	size_t total_read = 0;
	InRec cur_rec;
	char mainfname[2000];
	char *covpos=0;

	/* common main intro */
	writeHeader(destination);
	/* /common main intro */

	input_id = H5Fopen(argv[1], H5F_ACC_RDONLY, H5P_DEFAULT);
	if (input_id<0) abort();

	/* we need the original hdf5 to obtain the gaia ids; their filenames
	are the input filesnames minus the cov. */
	strncpy(mainfname, argv[1], 2000);
	covpos = strstr(mainfname, "_cov");
	strcpy(covpos, covpos+4);
	main_id = H5Fopen(mainfname, H5F_ACC_RDONLY, H5P_DEFAULT);
	if (main_id<0) abort();

	HDFGUARD(H5Sselect_hyperslab(memspace, H5S_SELECT_SET, null_offset, NULL, chunk_size, NULL));
  float arr_stellar_params_cov_triu[CHUNK_SIZE*21];
  datasets[0] = H5Dopen2(input_id, "stellar_params_cov_triu", H5P_DEFAULT);
  if (datasets[0]<0) abort();
  int64_t arr_gdr3_source_id[CHUNK_SIZE];
  datasets[1] = H5Dopen2(main_id, "gdr3_source_id", H5P_DEFAULT);
  if (datasets[1]<0) abort();

	arr_colspace = H5Dget_space(datasets[0]);
	colspace = H5Dget_space(datasets[1]);

	rank = H5Sget_simple_extent_ndims(colspace);
	if (rank>1) abort();
	H5Sget_simple_extent_dims(colspace, dims, NULL);
	nrecs = dims[0];
	while (total_read<nrecs) {

		Field *tuple;
		context = inputLine;
		if (!setjmp(ignoreRecord)) {

			if (index_in_chunk>=CHUNK_SIZE) {
				offsets[0] = total_read;
				arr_offsets[0] = total_read;
				if (total_read+chunk_size[0]>nrecs) {
					chunk_size[0] = nrecs-total_read;
					arr_chunk_size[0] = chunk_size[0];
					HDFGUARD(H5Sselect_hyperslab(memspace, H5S_SELECT_SET,		
					  null_offset, NULL, chunk_size, NULL));
        	HDFGUARD(H5Sselect_hyperslab(arr_memspace, H5S_SELECT_SET,
          	arr_null_offsets, NULL, arr_chunk_size, NULL));
				}

				HDFGUARD(H5Sselect_hyperslab(colspace, H5S_SELECT_SET,  offsets, NULL, chunk_size, NULL));
				HDFGUARD(H5Sselect_hyperslab(arr_colspace, H5S_SELECT_SET,
					arr_offsets, NULL, arr_chunk_size, NULL));
				HDFGUARD(H5Sselect_hyperslab(colspace, H5S_SELECT_SET,
					offsets, NULL, chunk_size, NULL));
				HDFGUARD(H5Dread(datasets[1], H5T_NATIVE_LLONG, memspace,
					colspace, H5P_DEFAULT, arr_gdr3_source_id));
				HDFGUARD(H5Dread(datasets[0], H5T_NATIVE_FLOAT, arr_memspace,
					arr_colspace, H5P_DEFAULT, arr_stellar_params_cov_triu));

			index_in_chunk = 0;
		}
		memcpy(cur_rec.stellar_params_cov_triu, &arr_stellar_params_cov_triu[index_in_chunk*21], 21*sizeof(float));
		cur_rec.gdr3_source_id = arr_gdr3_source_id[index_in_chunk];
		total_read += 1;
		index_in_chunk += 1;
		tuple = getTuple(&cur_rec, total_read-1);

			if (!tuple) {
				handleBadRecord("Bad input line at record %d", recCount);
			}
			writeTuple(tuple, QUERY_N_PARS, destination);
			context = NULL;
			recCount ++;
			if (!(recCount%1000)) {
				fprintf(stderr, "%08d\r", recCount);
				fflush(stderr);
			}
		}

	}

	writeEndMarker(destination);
	fprintf(stderr, "%08d records done.\n", recCount);
}

