/*
  This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.

  Author: Uwe Schulzweida

*/

#include <cdi.h>

#include "process_int.h"
#include "varray.h"

class TestModuleTestdata
{
  CdoStreamID streamID1;
  int taxisID1;
  int vlistID1;

  CdoStreamID streamID2;
  int taxisID2;

  size_t gridsize;
  FILE *fp;

  Varray<double> array;
  Varray<float> fval;
  Varray<int> ival;
  Varray<unsigned char> cval;
  Varray<unsigned char> cval2;

public:
  void
  init(void *process)
  {
    cdo_initialize(process);

    operator_check_argc(0);

    streamID1 = cdo_open_read(0);

    vlistID1 = cdo_stream_inq_vlist(streamID1);
    taxisID1 = vlistInqTaxis(vlistID1);

    streamID2 = cdo_open_write(1);

    int vlistID2 = vlistDuplicate(vlistID1);
    taxisID2 = taxisDuplicate(taxisID1);
    vlistDefTaxis(vlistID2, taxisID2);

    cdo_def_vlist(streamID2, vlistID2);

    gridsize = vlistGridsizeMax(vlistID1);
    array = Varray<double>(gridsize);
    fval = Varray<float>(gridsize);
    ival = Varray<int>(gridsize);
    cval = Varray<unsigned char>(gridsize * 4);
    cval2 = Varray<unsigned char>(gridsize * 4);

    fp = std::fopen("testdata", "w");
  }
  void
  run()
  {
    int tsID2 = 0;
    int tsID1 = 0;
    while (true)
      {
        const auto nrecs = cdo_stream_inq_timestep(streamID1, tsID1);
        if (nrecs == 0) break;

        cdo_taxis_copy_timestep(taxisID2, taxisID1);
        cdo_def_timestep(streamID2, tsID2);

        for (int recID = 0; recID < nrecs; ++recID)
          {
            int varID, levelID;
            cdo_inq_record(streamID1, &varID, &levelID);
            cdo_def_record(streamID2, varID, levelID);

            size_t nmiss;
            cdo_read_record(streamID1, array.data(), &nmiss);

            gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
            for (size_t i = 0; i < gridsize; ++i)
              {
                fval[i] = (float) array[i];

                memcpy(&ival[i], &fval[i], 4);
                memcpy(&cval[i * 4], &fval[i], 4);

                cval2[i + gridsize * 0] = cval[i * 4 + 0];
                cval2[i + gridsize * 1] = cval[i * 4 + 1];
                cval2[i + gridsize * 2] = cval[i * 4 + 2];
                cval2[i + gridsize * 3] = cval[i * 4 + 3];

                if (tsID1 == 0 && recID == 0)
                  printf("%4zu %3u %3u %3u %3u %d %g\n", i, (unsigned int) cval[4 * i + 0], (unsigned int) cval[4 * i + 1],
                         (unsigned int) cval[4 * i + 2], (unsigned int) cval[4 * i + 3], ival[i], fval[i]);
              }

            cdo_write_record(streamID2, array.data(), nmiss);

            fwrite(cval.data(), 4, gridsize, fp);
          }

        tsID1++;
        tsID2++;
      }
  }
  void
  close()
  {
    std::fclose(fp);
    cdo_stream_close(streamID1);
    cdo_stream_close(streamID2);

    cdo_finish();
  }
};

void *
Testdata(void *process)
{
  TestModuleTestdata testdata;

  testdata.init(process);
  testdata.run();
  testdata.close();

  return nullptr;
}
