#include <cdi.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>

#include "util_files.h"
#include "cdo_options.h"
#include "cdo_vlist.h"
#include "readline.h"

#include "cdo_default_values.h"

bool
FileUtils::file_exists(const std::string &fileName)
{
  struct stat buf;
  auto status = stat(fileName.c_str(), &buf);
  return (status == 0) && (S_ISREG(buf.st_mode) && buf.st_size > 0);
}

bool
FileUtils::user_file_overwrite(const std::string &fileName)
{
  auto status = false;

  if (!Options::silentMode && cdo::stdinIsTerminal && cdo::stderrIsTerminal)
    {
      fprintf(stderr, "File %s already exists, overwrite? (yes/no): ", fileName.c_str());
      char line[1024];
      cdo::readline(stdin, line, 1024);
      char *pline = line;
      while (isspace((int) *pline)) pline++;
      auto len = strlen(pline);
      if (len == 3)
        {
          if (std::strncmp(pline, "yes", 3) == 0 || std::strncmp(pline, "YES", 3) == 0) status = true;
        }
      else if (len == 1)
        {
          if (pline[0] == 'y' || pline[0] == 'Y') status = true;
        }
    }

  return status;
}

off_t
FileUtils::size(const char *filename)
{
  off_t filesize = 0;

  if (filename[0] != '(') /* && filename[1] != 'p') */
    {
      struct stat buf;
      if (stat(filename, &buf) == 0) filesize = buf.st_size;
    }

  return filesize;
}

static std::string
gen_file_suffix(int filetype, const std::string &referenceName, int vlistID)
{
  std::string suffix;
  auto foundSuffix = false;
  auto isCompSZ = false;

  if (filetype == CdoDefault::FileType && CdoDefault::DataType == -1 && CdoDefault::Byteorder == -1)
    {
      size_t len = 0;
      if (referenceName.size() > 0 && referenceName[0] != '-' && referenceName[0] != '.') len = referenceName.size();

      if (len > 2)
        {
          auto pos = referenceName.find_last_of('.');
          if (pos > 1 && pos < (referenceName.size() - 1))
            {
              auto result = referenceName.substr(pos + 1);
              auto firstchar = tolower(result[1]);
              switch (firstchar)
                {
                case 'g':
                  if (CdoDefault::FileType == CDI_FILETYPE_GRB || CdoDefault::FileType == CDI_FILETYPE_GRB2) foundSuffix = true;
                  break;
                case 'n':
                  if (CdoDefault::FileType == CDI_FILETYPE_NC || CdoDefault::FileType == CDI_FILETYPE_NC2
                      || CdoDefault::FileType == CDI_FILETYPE_NC4 || CdoDefault::FileType == CDI_FILETYPE_NC4C
                      || CdoDefault::FileType == CDI_FILETYPE_NC5)
                    foundSuffix = true;
                  break;
                case 's':
                  if (CdoDefault::FileType == CDI_FILETYPE_SRV) foundSuffix = true;
                  break;
                case 'e':
                  if (CdoDefault::FileType == CDI_FILETYPE_EXT) foundSuffix = true;
                  break;
                case 'i':
                  if (CdoDefault::FileType == CDI_FILETYPE_IEG) foundSuffix = true;
                  break;
                }

              if (foundSuffix)
                {
                  for (int i = 0, n = result.size(); i < n; ++i)
                    {
                      if (result[i] == '.' || isalnum(result[i])) suffix += result[i];
                    }
                }
            }
        }
    }

  if (!foundSuffix)
    {
      suffix += streamFilesuffix(CdoDefault::FileType);
      if (CdoDefault::FileType == CDI_FILETYPE_GRB && vlist_is_szipped(vlistID)) isCompSZ = true;
    }

  if (CdoDefault::FileType == CDI_FILETYPE_GRB && Options::cdoCompType == CDI_COMPRESS_SZIP) isCompSZ = true;
  if (isCompSZ) suffix += ".sz";

  return suffix;
}

std::string
FileUtils::gen_suffix(int filetype, int vlistID, const std::string &referenceName)
{
  std::string suffix;
  if (std::strncmp(cdo::File_Suffix, "NULL", 4) != 0)
    {
      if (cdo::File_Suffix[0] != 0) { suffix = cdo::File_Suffix; }
      else { suffix = gen_file_suffix(filetype, referenceName, vlistID); }
    }
  return suffix;
}
