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

  Copyright (C) 2003-2021 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 <cassert>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cdi.h>

#include <regex>

std::vector<std::string>
split_string(const std::string &str, const std::string &delimiter)
{
  std::regex regex(delimiter);
  return { std::sregex_token_iterator(str.begin(), str.end(), regex, -1), std::sregex_token_iterator() };
}

std::string
string_to_upper(std::string p_str)
{
  std::transform(p_str.begin(), p_str.end(), p_str.begin(), [](unsigned char c) { return std::toupper(c); });
  return p_str;
}

std::string
string_to_lower(std::string p_str)
{
  std::transform(p_str.begin(), p_str.end(), p_str.begin(), [](unsigned char c) { return std::tolower(c); });
  return p_str;
}

void
cstr_to_lower_case(char *str)
{
  if (str)
    for (size_t i = 0; str[i]; ++i) str[i] = (char) tolower((int) str[i]);
}

void
cstr_to_upper_case(char *str)
{
  if (str)
    for (size_t i = 0; str[i]; ++i) str[i] = (char) toupper((int) str[i]);
}

static void
trim_flt(char *ss)
{
  char *cp = ss;
  if (*cp == '-') cp++;
  while (isdigit((int) *cp) || *cp == '.') cp++;
  if (*--cp == '.') return;

  char *ep = cp + 1;
  while (*cp == '0') cp--;
  cp++;
  if (cp == ep) return;
  while (*ep) *cp++ = *ep++;
  *cp = '\0';

  return;
}

char *
double_to_att_str(int digits, char *attstr, size_t len, double value)
{
  const int ret = snprintf(attstr, len, "%#.*g", digits, value);
  assert(ret != -1 && ret < (int) len);
  trim_flt(attstr);
  return attstr;
}

const char *
tunit_to_cstr(int tunits)
{
  // clang-format off
  if      ( tunits == TUNIT_YEAR )       return ("years");
  else if ( tunits == TUNIT_MONTH )      return ("months");
  else if ( tunits == TUNIT_DAY )        return ("days");
  else if ( tunits == TUNIT_12HOURS )    return ("12hours");
  else if ( tunits == TUNIT_6HOURS )     return ("6hours");
  else if ( tunits == TUNIT_3HOURS )     return ("3hours");
  else if ( tunits == TUNIT_HOUR )       return ("hours");
  else if ( tunits == TUNIT_30MINUTES )  return ("30minutes");
  else if ( tunits == TUNIT_QUARTER )    return ("15minutes");
  else if ( tunits == TUNIT_MINUTE )     return ("minutes");
  else if ( tunits == TUNIT_SECOND )     return ("seconds");
  else                                   return ("unknown");
  // clang-format on
}

const char *
calendar_to_cstr(int calendar)
{
  // clang-format off
  if      ( calendar == CALENDAR_STANDARD )  return ("standard");
  else if ( calendar == CALENDAR_GREGORIAN ) return ("gregorian");
  else if ( calendar == CALENDAR_PROLEPTIC ) return ("proleptic_gregorian");
  else if ( calendar == CALENDAR_360DAYS )   return ("360_day");
  else if ( calendar == CALENDAR_365DAYS )   return ("365_day");
  else if ( calendar == CALENDAR_366DAYS )   return ("366_day");
  else                                       return ("unknown");
  // clang-format on
}
