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

  Copyright (C) 2003-2020 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 <climits>
#include <cerrno>
#include <cstdlib>
#include <cfloat>

#include "cdi.h"
#include "parse_literals.h"

int
literalGetDatatype(const std::string &literal)
{
  if (!literal.empty())
    {
      char *endptr;
      errno = 0;
      const long lval = strtol(literal.c_str(), &endptr, 10);
      if (errno == 0 && *endptr == 0)
        return CDI_DATATYPE_INT32;
      else if (errno == 0 && *(endptr + 1) == 0 && (*endptr == 's' || *endptr == 'b'))
        {
          if (*endptr == 's' && lval >= SHRT_MIN && lval <= SHRT_MAX)
            return CDI_DATATYPE_INT16;
          else if (*endptr == 'b' && lval >= SCHAR_MIN && lval <= SCHAR_MAX)
            return CDI_DATATYPE_INT8;
        }
      else
        {
          errno = 0;
          const double dval = strtod(literal.c_str(), &endptr);
          if (errno == 0 && *endptr == 0)
            return CDI_DATATYPE_FLT64;
          else if (errno == 0 && *(endptr + 1) == 0)
            {
              if (*endptr == 'f' && dval >= -FLT_MAX && dval <= FLT_MAX) return CDI_DATATYPE_FLT32;
            }
        }
    }

  return -1;
}

int
literalsFindDatatype(const int n, const std::vector<std::string> &literals)
{
  int dtype = -1;

  if (n)
    {
      dtype = literalGetDatatype(literals[0]);
      if (dtype != -1)
        for (int i = 1; i < n; ++i)
          {
            const int xtype = literalGetDatatype(literals[i]);
            if (dtype != xtype)
              {
                if (xtype == CDI_DATATYPE_FLT32 || xtype == CDI_DATATYPE_FLT64)
                  {
                    if (dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64)
                      {
                        if (xtype > dtype) dtype = xtype;
                      }
                    else
                      dtype = xtype;
                  }
                else
                  {
                    if (!(dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64))
                      {
                        if (xtype > dtype) dtype = xtype;
                      }
                    else
                      dtype = xtype;
                  }
              }
          }
    }

  return dtype;
}

int
literal2int(const std::string &literal)
{
  int ival = INT_MAX;

  if (!literal.empty())
    {
      char *endptr;
      ival = strtol(literal.c_str(), &endptr, 10);
    }

  return ival;
}

double
literal2double(const std::string &literal)
{
  double dval = DBL_MAX;

  if (!literal.empty())
    {
      char *endptr;
      dval = strtod(literal.c_str(), &endptr);
    }

  return dval;
}

#ifdef TEST_LITERAL
int
main(void)
{
  std::vector<std::string> literals
      = { "127b", "-32768s", "-2147483647", "-1.e+36f", "1.e+308", "temperature", "surface pressure", "1000." };
  const int nliterals = literals.size();

  for (int i = 0; i < nliterals; ++i)
    {
      const int dtype = literalGetDatatype(literals[i]);
      printf("%d %s type = %d", i + 1, literals[i].c_str(), dtype);
      if (dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32)
        {
          const auto ival = literal2int(literals[i]);
          printf("  ival = %d", ival);
        }
      else if (dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64)
        {
          const auto dval = literal2double(literals[i]);
          printf("  dval = %g", dval);
        }
      else
        {
          printf("  sval = '%s'", literals[i].c_str());
        }

      printf("\n");
    }

  return 0;
}
#endif
