/*
 * =====================================================================================
 *
 *       Filename:  mklink.c 
 *
 *    Description:  Example code for linking a dimension.
 *
 *        Version:  1.0
 *        Created:  07/15/2016 11:21:49 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Eugen Betke (betke@dkrz.de), Julian Kunkel (juliankunkel@googlemail.com)
 *   Organization:  Deutsches Klimarechenzentrum / German Climate Computing Center
 *
 * =====================================================================================
 */


#include <mpi.h>
#include <netcdf.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#define TIMEIDX 0
#define LATIDX 1
#define LONIDX 2

#define NTIME 4

int main(int argc, char ** argv){
  int ret;
	const char * gridfile = "grid.nc";
  const char * datafile = "data.nc";

  int grid_ncid;
	int data_ncid;

  int var;
  const int dimsize = 3;
	int dimids[dimsize];
	int varids[dimsize];
	size_t nlat = 6;
	size_t nlon = 5;
	size_t ntime = 4;
	float timedata[NTIME];

  MPI_Init(& argc, & argv);

	ret = nc_open(gridfile, NC_NOWRITE, &grid_ncid);
	assert(ret == NC_NOERR);

	ret = nc_create(datafile, NC_NETCDF4, &data_ncid);
	assert(ret == NC_NOERR);

	// set link to lat dimension 
	ret = nc_def_dim_external(data_ncid, grid_ncid, "lat", &dimids[LATIDX]);
	assert(ret == NC_NOERR);
	nc_inq_dimlen(data_ncid, dimids[LATIDX], &nlat);
	assert(ret == NC_NOERR);

	// set link to lon dimension 
	ret = nc_def_dim_external(data_ncid, grid_ncid, "lon", &dimids[LONIDX]);
	assert(ret == NC_NOERR);
	nc_inq_dimlen(data_ncid, dimids[LONIDX], &nlon);
	assert(ret == NC_NOERR);

	// create labels for time dimension
	for (int i = 0; i < NTIME; ++i) {
		timedata[i] = 1000.5 + i * 0.75;
	}

	// create a local, unlimited, labeled time dimension
	const size_t start[] = {0};
	const size_t count[] = {NTIME};
	ret = nc_def_dim(data_ncid, "time", NC_UNLIMITED, &dimids[TIMEIDX]);
	assert(ret == NC_NOERR);
	ret = nc_def_var(data_ncid, "time", NC_FLOAT, 1, &dimids[TIMEIDX], &varids[TIMEIDX]);
	assert(ret == NC_NOERR);
	ret = nc_put_vara(data_ncid, varids[TIMEIDX], start, count, &timedata);
	assert(ret == NC_NOERR);

	int (*values)[nlat][nlon] = malloc(ntime * sizeof(*values)); 

	for (int time = 0; time < ntime; ++time) {
		for (int lat = 0; lat < nlat; ++lat) {
			for (int lon = 0; lon < nlon; ++lon) {
				values[time][lat][lon] = lat * lon * time;
			}
		}
	}

	// nc_set_var_chunk_cache (int ncid, int varid, size_t size, size_t nelems, float preemption)
	ret = nc_def_var(data_ncid, "var1", NC_INT, dimsize, dimids, & var);
	assert(ret == NC_NOERR);

	ret = nc_enddef(data_ncid);
	assert(ret == NC_NOERR);

	size_t countp[] = {1, nlat, nlon};

	// writing data
	for(int time=0; time < ntime; time++){
		size_t startp[] = {time, 0, 0};
		ret = nc_put_vara_int(data_ncid, var, startp, countp, &values[time][0][0]);
		assert(ret == NC_NOERR);
	}

	// clean up
	free(values);
	nc_close(grid_ncid);
	nc_close(data_ncid);
	MPI_Finalize();
	return 0;
}

