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

  Author: Uwe Schulzweida

*/

#include <climits>
#include <cerrno>
#include <cstdlib>
#include <cfloat>

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

int
literal_get_datatype(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
literals_find_datatype(const int n, const std::vector<std::string> &literals)
{
  int dtype = -1;

  if (n)
    {
      dtype = literal_get_datatype(literals[0]);
      if (dtype != -1)
        for (int i = 1; i < n; ++i)
          {
            const int xtype = literal_get_datatype(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
literal_to_int(const std::string &literal)
{
  int ival = INT_MAX;

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

  return ival;
}

double
literal_to_double(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 = literal_get_datatype(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 = literal_to_int(literals[i]);
          printf("  ival = %d", ival);
        }
      else if (dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64)
        {
          const auto dval = literal_to_double(literals[i]);
          printf("  dval = %g", dval);
        }
      else
        {
          printf("  sval = '%s'", literals[i].c_str());
        }

      printf("\n");
    }

  return 0;
}
#endif
