#include "stdafx.h"
#include "aplAggr.h"

#ifdef _MFC_VER
	#ifdef _DEBUG
		#define new DEBUG_NEW
	#endif
#endif

#define aplCODEPAGE_Win_Cyrillic 1251
extern int aplUtf8StrLen(const char *str);

UINT CaplStringAdapter::m_st_encoding = aplCODEPAGE_Win_Cyrillic; // Если надо текущее в системе, то должно быть CP_ACP

CaplStringAdapter::CaplStringAdapter() :
	m_buffer_ansi(NULL)
	, m_buffer_utf(NULL)
	, m_size_ANSI(0)
	, m_size_UTF(0)
#ifdef _MFC_VER
	, m_bIsAnsiUtf8(false)
#else
	, m_bIsAnsiUtf8(true)
#endif
	, m_bIsError(false)
	{
}

CaplStringAdapter::~CaplStringAdapter()
{
	if (0!=m_buffer_ansi && 0!=m_size_ANSI) delete[] m_buffer_ansi; // Если 0==m_size_ANSI, то это ссылка на чужую строку
	if (0!=m_buffer_utf && 0!=m_size_UTF) delete[] m_buffer_utf; // Если 0==m_size_UTF, то это ссылка на чужую строку
}

size_t CaplStringAdapter::SetSizeANSI(size_t new_size)
{
	// удаление строки
	if (new_size == 0)
	{
		if (0!=m_buffer_ansi && 0!=m_size_ANSI) delete[] m_buffer_ansi; // Если 0==m_size_ANSI, то это ссылка на чужую строку
		m_buffer_ansi = NULL;
		m_size_ANSI = 0;
		return 0;
	}

	if (new_size <= m_size_ANSI) return m_size_ANSI;

	// выделение памяти под ANSI-строку
	char* new_buffer_ansi = new char[new_size];
	new_buffer_ansi[0]='\0';
	if (m_buffer_ansi) 
	{
		// Если 0==m_size_ANSI, то это ссылка на чужую строку
		if(0==m_size_ANSI) strcpy(new_buffer_ansi, m_buffer_ansi);
		else
		{
			strncpy(new_buffer_ansi, m_buffer_ansi, m_size_ANSI);
			delete[] m_buffer_ansi;
		}
	}
	m_size_ANSI = new_size;
	m_buffer_ansi = new_buffer_ansi;

	return m_size_ANSI;
}

size_t CaplStringAdapter::SetSizeUTF(size_t new_size)
{
	// удаление строки
	if (new_size == 0)
	{
		if (0!=m_buffer_utf && 0!=m_size_UTF) delete[] m_buffer_utf;  // Если 0==m_size_UTF, то это ссылка на чужую строку

		m_buffer_utf = NULL;
		m_size_UTF = 0;
		return 0;
	}

	if (new_size <= m_size_UTF) return m_size_UTF;

	// выделение памяти под UNICODE-строку
	wchar_t* new_buffer_utf = new wchar_t[new_size];
	new_buffer_utf[0]=L'\0';
	if (m_buffer_utf)
	{
		// Если 0==m_size_UTF, то это ссылка на чужую строку
		if(0==m_size_UTF) wcscpy(new_buffer_utf, m_buffer_utf);
		else
		{
			wcsncpy(new_buffer_utf, m_buffer_utf,m_size_UTF);
			delete[] m_buffer_utf;
		}
	}
	m_size_UTF = new_size;
	m_buffer_utf = new_buffer_utf;

	return m_size_UTF;
}

CaplStringAdapter::CaplStringAdapter(const char* c_str) :
	m_buffer_ansi(NULL)
	, m_buffer_utf(NULL)
	, m_size_ANSI(0)
	, m_size_UTF(0)
#ifdef _MFC_VER
  , m_bIsAnsiUtf8(false)
#else
  , m_bIsAnsiUtf8(true)
#endif
  , m_bIsError(false)
  , m_sError(_T(""))
{
	*this = c_str;
}

CaplStringAdapter::CaplStringAdapter(const wchar_t* w_str) :
	m_buffer_ansi(NULL)
	, m_buffer_utf(NULL)
	, m_size_ANSI(0)
	, m_size_UTF(0)
#ifdef _MFC_VER
  , m_bIsAnsiUtf8(false)
#else
  , m_bIsAnsiUtf8(true)
#endif
  , m_bIsError(false)
  , m_sError(_T(""))
{
	*this = w_str;
}

CaplStringAdapter& CaplStringAdapter::operator=(const char* c_str)
{
	SetSizeUTF(0);
	SetSizeANSI(0);

	if(0 == c_str)
	{
		return *this;
	}

	// ANSI
	m_buffer_ansi = const_cast<char*>(c_str);
	return *this;
}

CaplStringAdapter& CaplStringAdapter::operator=(const wchar_t* w_str)
{
	SetSizeANSI(0);
	SetSizeUTF(0);

	if(0 == w_str)
	{
		return *this;
	}

	// UNICODE
	m_buffer_utf = const_cast<wchar_t*>(w_str);

	return *this;
}

// оператор преобразования в ANSI-строку
CaplStringAdapter::operator LPCSTR() throw()
{
	return const_cast<LPCSTR>(operator LPSTR());
}

CaplStringAdapter::operator LPSTR() throw()
{
	if(0!=m_buffer_ansi) return m_buffer_ansi;
	if(0!=m_buffer_utf)
	{
		/* wcstombs не работает корректно с русским под QtCreator, а под MSVC  требует локали
		size_t length = wcslen(m_buffer_utf);
		SetSizeANSI(length+1);
		wcstombs(m_buffer_ansi, m_buffer_utf, length);
		m_buffer_ansi[length] = '\0';
		*/

		if(L'\0'==m_buffer_utf[0]) 
		{
			SetSizeANSI(1);
			m_buffer_ansi[0] = '\0';
			return m_buffer_ansi;
		}

#ifndef __GNUC__
		UINT encoding = m_st_encoding;/*CP_ACP;*/ //если дефолтная кодировка в Windows отличается от 1251, в результате перевода исходной юникодной строки с русскими символами получим полную хрень
		if(m_bIsAnsiUtf8) encoding = CP_UTF8;

		int la = ::WideCharToMultiByte(encoding, 0, m_buffer_utf, -1, NULL, 0, NULL, NULL);
		if(la<0) la=0;
		SetSizeANSI(la + 1);
		m_buffer_ansi[0] = '\0';
		if(la>0)
		{
			int len= ::WideCharToMultiByte(encoding, 0,  m_buffer_utf, -1, m_buffer_ansi, m_size_ANSI,  NULL, NULL);
			if(len<0) len=0; 
			m_buffer_ansi[len]='\0';
		}
#else

		aplTextEncoding TrgCoding=aplANSI;
		if(m_bIsAnsiUtf8) TrgCoding=aplUTF8;

		int lw = wcslen(m_buffer_utf);
		int wz=(lw+1)*sizeof(wchar_t);

		BYTE *out_buf=0;
		int out_buf_len=0;
		m_bIsError = !bConvertTextWithIconv(aplCurWcharCode,(BYTE*)m_buffer_utf,wz,TrgCoding,out_buf,out_buf_len,0,&m_sError);

		if(0!=out_buf) {m_buffer_ansi=(char*)out_buf; m_size_ANSI=(int)out_buf_len;}
		else { SetSizeANSI(1); m_buffer_ansi[0]='\0';}
		
#endif
	}
	return m_buffer_ansi;
}

// оператор преобразования в UNICODE-строку
CaplStringAdapter::operator LPCWSTR() throw()
{
	return const_cast<LPCWSTR>(operator LPWSTR());
}

CaplStringAdapter::operator LPWSTR() throw()
{
	if(0!=m_buffer_utf) return m_buffer_utf;
	if(0!=m_buffer_ansi)
	{
		/* wcstombs не работает корректно с русским под QtCreator, а под MSVC  требует локали
		size_t length = strlen(m_buffer_ansi);
		SetSizeUTF(length+1);
		mbstowcs(m_buffer_utf, m_buffer_ansi, length);
		m_buffer_utf[length] = L'\0';
		*/
		
		if('\0'==m_buffer_ansi[0]) 
		{
			SetSizeUTF(1);
			m_buffer_utf[0]=L'\0';
			return m_buffer_utf;
		}

#ifndef __GNUC__
		UINT encoding = m_st_encoding;
		if(m_bIsAnsiUtf8) encoding = CP_UTF8;

		int lw = ::MultiByteToWideChar(encoding, 0, m_buffer_ansi, -1, NULL, 0);
		if(lw <0) lw=0;
		SetSizeUTF(lw + 1);
		m_buffer_utf[0]=L'\0';
		if(lw>0) 
		{
			int len= ::MultiByteToWideChar(encoding, 0,  m_buffer_ansi, -1, m_buffer_utf, m_size_UTF);
			if(len<0) len=0;
			m_buffer_utf[len] = L'\0'; // На всякий случай
		}
#else

		aplTextEncoding SrcCoding=aplANSI;
		if(m_bIsAnsiUtf8) SrcCoding=aplUTF8;

		int la = strlen(m_buffer_ansi)+1;

		BYTE *out_buf=0;
		int out_buf_len=0;
		m_bIsError = !bConvertTextWithIconv(SrcCoding,(BYTE*)m_buffer_ansi,la,aplCurWcharCode,out_buf,out_buf_len,0,&m_sError);

		if(0!=out_buf) {m_buffer_utf=(wchar_t*)out_buf; m_size_UTF=(int)out_buf_len;}
		else { SetSizeUTF(1); m_buffer_utf[0]='\0';}

#endif

	}
	return m_buffer_utf;
}

//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
size_t aplGetMaxBYTEInCharForEncoding(aplTextEncoding coding)
{
	switch (coding)
	{
	case aplANSI: 
	case aplCP866:
		return 1;
		break;
	case aplUTF8:
	case aplUCS2:
	case aplUTF16BE:
		return 2;
		break;
	case aplUTF32LE:
	case aplUTF32BE:
		return 4;
		break;
	default:
		return 0;
	}
	return 0;
}
//*************************************************************************************

size_t aplGetMinBYTEInCharForEncoding(aplTextEncoding coding)
{
	switch (coding)
	{
	case aplANSI: 
	case aplUTF8:
	case aplCP866:
		return 1;
		break;
	case aplUCS2:
	case aplUTF16BE:
		return 2;
		break;
	case aplUTF32LE:
	case aplUTF32BE:
		return 4;
		break;
	default:
		return 0;
	}
	return 0;
}
//*************************************************************************************
const char* aplGetCodingNameForIcov(aplTextEncoding coding)
{
	static const char* sAnsi="CP1251";
	static const char* sUtf8="UTF-8";
	static const char* sUcs2="UCS-2LE";
	static const char* sUtf16BE="UCS-2BE";
	static const char* sUtf32LE="UCS-4LE";
	static const char* sUtf32BE="UCS-4BE";
	static const char* sCp866="CP866";

	switch (coding)
	{
	case aplANSI: return sAnsi; break;
	case aplUTF8: return sUtf8; break;
	case aplUCS2: return sUcs2; break;
	case aplUTF16BE: return sUtf16BE; break;
	case aplUTF32LE: return sUtf32LE; break;
	case aplUTF32BE: return sUtf32BE; break;
	case aplCP866: return sCp866; break;
	default:
		return 0;
	}
	return 0;
}
//*************************************************************************************
