#include <amsstring4/amsstring4.hpp>

namespace ams
{
    
//snprintf, vsnprintf should now be part of the C++ standard library
//as of C++11, so I don't think I need quite as elaborate a compatibility
//shim as in the previous library.
//It *should* compile with MinGW and Visual Studio.


//src must be a NULL terminated string, or have more indices than the size of the destination buffer
//I'm seeing platform specific memory leaks in the strncpy and strcpy_s implementations in valgrind
//This is a dirt simple function, I shouldn't *need* to depend on a platform specific implementation,
//... so, writing my own.
//
//This function copies the string src to dest. 
//It stops when either size-1 characters have been copied to
//dest, or a null terminator has been encountered in src.
//
//The return value is the number of characters copied, excluding the null terminator
//or an error code.
//
//All additional positions in dest are padded with null terminators. Size is intended to be the size
//of the dest buffer.
int amsstrcpy_s(char *dest, int size, const char *src)
{
  int ret = 0;
  int I=0;
  char c='\0';

  if(dest==NULL)
  {
    ret = -2;
    return ret;
  }

  if(src==NULL)
  {
    ret = -1;
    return ret;
  }

  for(I=0;I<size-1;I++)
  {
    c = src[I];
    ret = I;

    if(c=='\0')
    {
      dest[I] = '\0';
      break;
    }
    
    dest[I] = c;
  }

  for(I=ret+1;I<size;I++)
  {
    dest[I] = '\0';
  }
  dest[size-1] = '\0';

  return ret;
}


//wrapper for strcpy_s and strncpy which should be portable between gnu and microsoft C libraries
//strcpy_s
//strncpy
// int amsstrcpy_s(char *dest, int size, const char *src)
// {
//   int ret = 0;
//   if(dest!=NULL)
//   {
//     if(src!=NULL)
//     {
//         #if defined(LINUX) || defined(linux) || defined(__linux__) || defined(__GNUC__)
//             //use strncpy
//             strncpy(dest,src,size);
//             ret = 0;
//             if(size>0)
//             {
//               dest[size-1] = '\0';
//             }
//         #elif defined(__MINGW32__) || defined(__MINGW64__) || defined(_WIN32)
//             //use strcpy_s
//             //ret = (int)strcpy_s(dest,size,src);
//             strcpy_s(dest,size,src);
//             ret = 0;
//             if(size>0)
//             {
//               dest[size-1] = '\0';
//             }
//         #else
//             #pragma message("amsstrcpy_s: Unsupported architecture - neither linux nor mingw64 nor msvc")
//         #endif
//     }
//     else
//     {
//         if(size>0)
//         {
//             dest[0] = '\0';
//             ret = -2; //src was NULL
//         }
//     }
//   }
//   else
//   {
//       ret = -1; //dest was a null pointer 
//   }
  
//   return ret;
// }


//sprintf_s
//snprintf
//
int amssprintf_s(char *s, int n, const char *format, ...)
{
  int ret = 0;

  va_list args;

  if(s==NULL) {ret = -1; return ret;}
  if(format==NULL) 
  {
    ret = -2;
    if(s!=NULL && n>0)
    {
      s[0] = '\0';
    } 
    return ret;
  }


  va_start(args, format);
  //exampleV(b, args);
  //va_arg(val,datatype)
  // if(s!=NULL)
  // {
    #if defined(LINUX) || defined(linux) || defined(__linux__) || defined(__GNUC__) || defined(__APPLE__) || defined(__MACH__)
        //use snprintf
        ret = (int)vsnprintf(s,n,format,args);
        s[n-1] = '\0';

    #elif defined(__MINGW32__) || defined(__MINGW64__) || defined(_WIN32)
        //use sprintf_s
        ret = (int)vsprintf_s(s,n,format,args);
    #else
        #pragma message("amssprintf_s: Unsupported architecture - neither linux nor mingw64 nor msvc")
    #endif
  //}

  va_end(args);
  return ret;
}

//Using the C library's sscanf function is more robust
//than atod or atof. It returns valid numbers for infs and nans
//Returns nan for any uninterpretable string
double amsstrtonum(const char *str)
{
  int q;
  double ret = std::numeric_limits<double>::quiet_NaN();

  if(str==NULL) return ret;

  try
  {
    //sscanf(s.cstring,"%lf",&ret);
    //stod(const std::string& str, std::size_t* pos)
    //calls std::strtod
    //strtod(const char *, &ptr)
    //wcstrtod
    //ret = atof(str); //old c-style parser
    q = sscanf(str,"%lf",&ret);
    if(q==0)
    {
      ret = std::numeric_limits<double>::quiet_NaN();
    }
  }
  catch(int e)
  {
    ret = std::numeric_limits<double>::quiet_NaN();
  }
  return ret;
}



};