#ifndef bqtWstringH
#define bqtWstringH

#include <string>

#define USE_ICONV 0

#if USE_ICONV
# include <iconv.h>
#else
# include <cuchar>
#endif

#ifdef WIN32
#define _GLIBCXX_USE_WCHAR_T 1
#endif

#undef putc
#undef puts

/* Converting a bytestream to wstring */
class wstringIn
{
#if USE_ICONV
    iconv_t converter;
    std::string charset;
    mutable std::string leftover;
#else
    mutable std::mbstate_t state{};
#endif
public:
    wstringIn();
    ~wstringIn();

#if USE_ICONV
    wstringIn(const char *setname);
    void SetSet(const char *setname);
#else
    inline void SetSet() {}
#endif

    const std::u32string puts(const std::string &s) const;
private:
    wstringIn(const wstringIn&);
    const wstringIn& operator=(const wstringIn&);
};

/* Converting a wstring to bytestream */
class wstringOut
{
#if USE_ICONV
    mutable iconv_t converter;
    mutable iconv_t tester;
    std::string charset;
#else
    mutable std::mbstate_t state{};
#endif
public:
    wstringOut();
    ~wstringOut();

#if USE_ICONV
    wstringOut(const char *setname);
    void SetSet(const char *setname);
#else
    inline void SetSet() {}
#endif

    const std::string putc(char32_t p) const { return puts(std::u32string(1, p)); }
    const std::string puts(const std::u32string &s) const;
    bool isok(char32_t p) const;
private:
    wstringOut(const wstringOut&);
    const wstringOut& operator=(const wstringOut&);
};

/* char to char32_t conversions - ASCII to UNICODE conversion */
inline char32_t AscToWchar(char c)
{ return static_cast<char32_t> (static_cast<unsigned char> (c)); }
extern const std::u32string AscToWstr(const std::string &s);

/* char32_t to char conversions - UNICODE to ASCII conversion */
extern const std::string WstrToAsc(const std::u32string &s);
extern char WcharToAsc(char32_t c);

/* Converts the given hex digit, to integer */
extern int Whex(char32_t p);

/* atoi() for char32_t pointers */
extern long atoi(const char32_t *p, int base=10);

///* swprintf() */
//const std::u32string wformat(const char32_t* fmt, ...);
#include "printf.hh"
template<typename...T>
std::u32string wformat(const char32_t* fmt, T&&... args)
{
    PrintfFormatter        Formatter;
    PrintfFormatter::State state;
    Formatter.MakeFrom(fmt);
    Formatter.Execute(state, std::forward<T>(args)...);
    return std::u32string(state.result.begin(), state.result.end());
}

/* UNICODE illegal character */
static const char32_t ilseq = 0xFFFD;

/* UNICODE signature character */
static const char32_t ucsig = 0xFEFF;

#endif
