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

  Copyright (C) 2003-2018 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

#include <cdi.h>

#include "cdo_int.h"
#include "pstream_int.h"

void
printAtts(int vlistID, int varOrGlobal, int natts, char *argument)
{
  char stdname[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
  int found = 0;
  if (varOrGlobal != CDI_GLOBAL)
    {
      vlistInqVarStdname(vlistID, varOrGlobal, stdname);
      vlistInqVarLongname(vlistID, varOrGlobal, longname);
      vlistInqVarUnits(vlistID, varOrGlobal, units);
      double misval = vlistInqVarMissval(vlistID, varOrGlobal);
      if (argument)
        {
          if (STR_IS_EQ("standard_name", argument) && stdname[0])
            {
              fprintf(stdout, "  standard_name = \"%s\"\n", stdname);
              found++;
            }
          else if (STR_IS_EQ("long_name", argument) && longname[0])
            {
              fprintf(stdout, "  long_name = \"%s\"\n", longname);
              found++;
            }
          else if (STR_IS_EQ("units", argument) && units[0])
            {
              fprintf(stdout, "  units = \"%s\"\n", units);
              found++;
            }
          else if (STR_IS_EQ("missing_value", argument))
            {
              fprintf(stdout, "  missing_value = \"%e\"\n", misval);
              found++;
            }
        }
      else
        {
          if (stdname[0]) fprintf(stdout, "  standard_name = \"%s\"\n", stdname);
          if (longname[0]) fprintf(stdout, "  long_name = \"%s\"\n", longname);
          if (units[0]) fprintf(stdout, "  units = \"%s\"\n", units);
          fprintf(stdout, "  missing_value = \"%e\"\n", misval);
        }
    }
  if (found == 0)
    {
      for (int i = 0; i < natts; i++)
        {
          char name[CDI_MAX_NAME];
          char *value = (char *) Malloc(4 * CDI_MAX_NAME * sizeof(char));
          int type, len;
          cdiInqAtt(vlistID, varOrGlobal, i, name, &type, &len);
          if (argument)
            {
              if (!STR_IS_EQ(argument, name))
                continue;
              else
                found++;
            }
          switch (type)
            {
            case CDI_DATATYPE_TXT:
              cdiInqAttTxt(vlistID, varOrGlobal, name, len, value);
              value[len] = '\0';
              fprintf(stdout, "  %s = \"%s\"\n", name, value);
              break;
            case CDI_DATATYPE_INT32:
              cdiInqAttInt(vlistID, varOrGlobal, name, len, (int *) value);
              fprintf(stdout, "  %s = %i\n", name, *(int *) value);
              break;
            case CDI_DATATYPE_FLT64:
              cdiInqAttFlt(vlistID, varOrGlobal, name, len, (double *) value);
              fprintf(stdout, "  %s = %e\n", name, *(double *) value);
              break;
            default: cdoWarning("Unsupported type %i name %s\n", type, name);
            }
          Free(value);
        }
    }
  if (argument && found == 0)
    {
      if (varOrGlobal != CDI_GLOBAL)
        cdoAbort("Could not find variable attribute %s in infile.", argument);
      else
        cdoAbort("Could not find global attribute %s in infile.", argument);
    }
}

void
check_varname_and_print(int vlistID, int nvars, char *checkvarname, char *attname)
{
  int varID = 0;
  for (varID = 0; varID < nvars; varID++)
    {
      char filevarname[CDI_MAX_NAME];
      vlistInqVarName(vlistID, varID, filevarname);
      if (!checkvarname || STR_IS_EQ(checkvarname, filevarname))
        {
          fprintf(stdout, "%s:\n", filevarname);
          int nfileattsvar;
          cdiInqNatts(vlistID, varID, &nfileattsvar);
          printAtts(vlistID, varID, nfileattsvar, attname);
          break;
        }
    }
  if (nvars == varID && checkvarname) cdoAbort("Could not find variable %s in infile.", checkvarname);
}

void *
Showattribute(void *process)
{
  const int delim = '@';
  cdoInitialize(process);

  int SHOWATTRIBUTE = cdoOperatorAdd("showattribute", 0, 0, NULL);
  int SHOWATTSVAR = cdoOperatorAdd("showattsvar", 0, 0, NULL);

  int operatorID = cdoOperatorID();

  int streamID = cdoStreamOpenRead(cdoStreamName(0));
  int vlistID = cdoStreamInqVlist(streamID);
  int nvars = vlistNvars(vlistID);

  int natts = operatorArgc();
  if (natts == 0 && operatorID != SHOWATTSVAR)
    cdoAbort("Parameter missing!");
  else if (natts == 0)
    check_varname_and_print(vlistID, nvars, NULL, NULL);
  else
    {
      char **params = operatorArgv();
      char buffer[CDI_MAX_NAME];
      for (int i = 0; i < natts; i++)
        {
          strcpy(buffer, params[i]);
          char *varname = NULL, *input = NULL;
          char *result = strrchr(buffer, delim);
          input = buffer;
          if (result == NULL)
            {
              if (operatorID == SHOWATTRIBUTE)
                {
                  fprintf(stdout, "Global:\n");
                  int nfileatts;
                  cdiInqNatts(vlistID, CDI_GLOBAL, &nfileatts);
                  printAtts(vlistID, CDI_GLOBAL, nfileatts, input);
                }
              else if (operatorID == SHOWATTSVAR)
                check_varname_and_print(vlistID, nvars, input, NULL);
            }
          else
            {
              if (operatorID == SHOWATTRIBUTE)
                {
                  input = result + 1;
                  *result = 0;
                  varname = buffer;
                  check_varname_and_print(vlistID, nvars, varname, input);
                }
              else if (operatorID == SHOWATTSVAR)
                check_varname_and_print(vlistID, nvars, input, NULL);
            }
        }
    }
  pstreamClose(streamID);

  cdoFinish();

  return 0;
}
