#include <iostream>
#include <locale>
#include <string>
#include <cstring>

std::wstring
to_wide_string (std::string const& str,
		std::locale        locale)
{
  typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type;
  codecvt_type const& cvt = std::use_facet<codecvt_type>(locale);
  mbstate_t state;
  const char *cbegin = str.data(), *cend = str.data() + str.size(), *cnext;
  wchar_t *wcnext;
  wchar_t wcbuf[80];
  std::wstring ret;

  std::memset(&state, 0, sizeof(mbstate_t));

  while (1)
    {
      std::codecvt_base::result res =
	cvt.in(state,
	       cbegin, cend, cnext,
	       wcbuf, wcbuf + (sizeof(wcbuf) / sizeof(wcbuf[0])), wcnext);

      if (res == std::codecvt_base::ok || std::codecvt_base::partial)
	{
	  std::cout << "1" << std::endl;
	  ret += std::wstring(wcbuf, wcnext);
	  if (cend == cnext)
	    break;
	}
      else if (res == std::codecvt_base::noconv)
	{
	  std::cout << "2" << std::endl;
	  ret += std::wstring(cbegin, cend);
	  break;
	}
      else if (res == std::codecvt_base::error)
	{
	  std::cout << "3" << std::endl;
	  break;
	}
      else
	break;

      std::cout << "4" << std::endl;
      cbegin = cnext;
    }

  return ret;
}

std::string
to_narrow_string (std::wstring const& str,
		  std::locale         locale)
{
  typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type;
  codecvt_type const& cvt = std::use_facet<codecvt_type>(locale);
  mbstate_t state;
  const wchar_t *wcbegin = str.data(), *wcend = str.data() + str.size(), *wcnext;
  char *cnext;
  char cbuf[80];
  std::string ret;

  std::memset(&state, 0, sizeof(mbstate_t));

  while (1)
    {
      std::codecvt_base::result res =
	cvt.out(state,
		wcbegin, wcend, wcnext,
		cbuf, cbuf + (sizeof(cbuf) / sizeof(cbuf[0])), cnext);

      if (res == std::codecvt_base::ok || std::codecvt_base::partial)
	{
	  std::cout << "1" << std::endl;
	  ret += std::string(cbuf, cnext);
	  if (wcend == wcnext)
	    break;
	}
      else if (res == std::codecvt_base::noconv)
	{
	  std::cout << "2" << std::endl;
	  ret += std::string(wcbegin, wcend);
	  break;
	}
      else if (res == std::codecvt_base::error)
	{
	  std::cout << "3" << std::endl;
	  break;
	}
      else
	break;

      std::cout << "4" << std::endl;
      wcbegin = wcnext;
    }

  return ret;
}

int main()
{
  std::locale::global(std::locale(""));
  std::cout.imbue(std::locale());
  std::wcerr.imbue(std::locale());

  std::string foo = "test: ABC ßè";
  std::wstring wfoo = to_wide_string(foo, std::wcerr.getloc());
  std::string cfoo = to_narrow_string(wfoo, std::cout.getloc());

  std::cout << foo << std::endl;
  std::wcerr << wfoo << std::endl;
  std::cout << cfoo << std::endl;


  return 0;
}
