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

  Author: Uwe Schulzweida

*/

/*
   This module contains the following operators:

      Ninfo      npar            Number of parameters
      Ninfo      nlevel          Number of levels
      Ninfo      nyear           Number of years
      Ninfo      nmon            Number of months
      Ninfo      ndate           Number of dates
      Ninfo      ntime           Number of timesteps
      Ninfo      ngridpoints     Number of gridpoints
      Ninfo      ngrids          Number of grids
*/

#include <cdi.h>

#include "process_int.h"

void *
Ninfo(void *process)
{
  enum
  {
    NYEAR,
    NMON,
    NDATE,
    NTIME,
    NPAR,
    NLEVEL,
    NGRIDPOINTS,
    NGRIDS
  };
  int varID;
  int date0 = 0;
  int day, mon0 = 0, mon, year0 = 0, year;

  cdo_initialize(process);

  // clang-format off
  cdo_operator_add("nyear"      , NYEAR      , 0, nullptr);
  cdo_operator_add("nmon"       , NMON       , 0, nullptr);
  cdo_operator_add("ndate"      , NDATE      , 0, nullptr);
  cdo_operator_add("ntime"      , NTIME      , 0, nullptr);
  cdo_operator_add("npar"       , NPAR       , 0, nullptr);
  cdo_operator_add("nlevel"     , NLEVEL     , 0, nullptr);
  cdo_operator_add("ngridpoints", NGRIDPOINTS, 0, nullptr);
  cdo_operator_add("ngrids"     , NGRIDS     , 0, nullptr);
  // clang-format on

  const auto operatorID = cdo_operator_id();
  const auto operfunc = cdo_operator_f1(operatorID);

  operator_check_argc(0);

  const auto streamID = cdo_open_read(0);
  const auto vlistID = cdo_stream_inq_vlist(streamID);

  const auto nvars = vlistNvars(vlistID);
  const auto taxisID = vlistInqTaxis(vlistID);
  const auto ntsteps = vlistNtsteps(vlistID);
  const auto ngrids = vlistNgrids(vlistID);

  VarList varList;
  varListInit(varList, vlistID);

  switch (operfunc)
    {
    case NYEAR:
      {
        int nyear = 0;
        int tsID = 0;
        if (ntsteps != 0)
          while (cdo_stream_inq_timestep(streamID, tsID))
            {
              const auto vdate = taxisInqVdate(taxisID);
              cdiDecodeDate(vdate, &year, &mon, &day);

              if (tsID == 0 || year0 != year)
                {
                  year0 = year;
                  nyear++;
                }

              tsID++;
            }
        fprintf(stdout, "%d\n", nyear);
        break;
      }
    case NMON:
      {
        int nmon = 0;
        int tsID = 0;
        if (ntsteps != 0)
          while (cdo_stream_inq_timestep(streamID, tsID))
            {
              const auto vdate = taxisInqVdate(taxisID);
              cdiDecodeDate(vdate, &year, &mon, &day);

              if (tsID == 0 || mon0 != mon)
                {
                  mon0 = mon;
                  nmon++;
                }

              tsID++;
            }
        fprintf(stdout, "%d\n", nmon);
        break;
      }
    case NDATE:
      {
        int ndate = 0;
        int tsID = 0;
        if (ntsteps != 0)
          while (cdo_stream_inq_timestep(streamID, tsID))
            {
              const auto vdate = taxisInqVdate(taxisID);

              if (tsID == 0 || date0 != vdate)
                {
                  date0 = vdate;
                  ndate++;
                }

              tsID++;
            }
        fprintf(stdout, "%d\n", ndate);
        break;
      }
    case NTIME:
      {
        int tsID = (ntsteps > 0) ? ntsteps : 0;
        if (tsID == 0)
          while (cdo_stream_inq_timestep(streamID, tsID)) tsID++;
        fprintf(stdout, "%d\n", tsID);
        break;
      }
    case NPAR: fprintf(stdout, "%d\n", nvars); break;
    case NLEVEL:
      for (varID = 0; varID < nvars; varID++)
        {
          fprintf(stdout, "%d\n", varList[varID].nlevels);
        }
      break;
    case NGRIDPOINTS:
      for (varID = 0; varID < nvars; varID++)
        {
          fprintf(stdout, "%zu\n", varList[varID].gridsize);
        }
      break;
    case NGRIDS: fprintf(stdout, "%d\n", ngrids); break;
    default: cdo_abort("operator not implemented!"); break;
    }

  cdo_stream_close(streamID);

  cdo_finish();

  return nullptr;
}
