/*
	TCString.h - TCString class
	Copyright (c) 2005-2008 Chervov Dmitry

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#pragma once

#include <windows.h>
#include <crtdbg.h>
#ifdef CHARARRAY_CONVERT
#include "TMyArray.h"
#endif
#include "newpluginapi.h"
#include "m_system.h"
#include "m_database.h"

__inline int My_lstrlen(LPCSTR lpString) { return (int)mir_strlen(lpString); }
__inline int My_lstrlen(LPCWSTR lpString) { return (int)mir_wstrlen(lpString); }
__inline int My_lstrcmp(LPCSTR lpString1, LPCSTR lpString2) { return mir_strcmp(lpString1, lpString2); }
__inline int My_lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2) { return mir_wstrcmp(lpString1, lpString2); }
__inline LPCSTR My_strstr(LPCSTR lpString1, LPCSTR lpString2) { return strstr(lpString1, lpString2); }
__inline LPWSTR My_strstr(LPCWSTR lpString1, LPCWSTR lpString2) { return (LPWSTR)wcsstr(lpString1, lpString2); }
__inline LPSTR My_lstrcpy(LPSTR lpString1, LPCSTR lpString2) { return mir_strcpy(lpString1, lpString2); }
__inline LPWSTR My_lstrcpy(LPWSTR lpString1, LPCWSTR lpString2) { return mir_wstrcpy(lpString1, lpString2); }
__inline LPSTR My_strncpy(LPSTR lpString1, LPCSTR lpString2, int Len) { return strncpy(lpString1, lpString2, Len); }
__inline LPWSTR My_strncpy(LPWSTR lpString1, LPCWSTR lpString2, int Len) { return wcsncpy(lpString1, lpString2, Len); }
__inline LPSTR My_strlwr(LPSTR lpString) { return _strlwr(lpString); }
__inline LPWSTR My_strlwr(LPWSTR lpString) { return _wcslwr(lpString); }

template <class T>
class TString
{
public:
	TString() : pBuf(NULL), nBufSize(0), nAllocSize(0) {}
	TString(const T *pStr) : pBuf(NULL), nBufSize(0), nAllocSize(0) { *this = pStr; }
	TString(const TString<T> &Str) : pBuf(NULL), nBufSize(0), nAllocSize(0) { *this = Str.pBuf; }
	~TString() { Free(); }

	int GetLen() const { return (nBufSize) ? (nBufSize - 1) : 0; };
	int IsEmpty() const { return (!GetLen()); };
	T *GetBuffer(int nNewLen = -1);
	void ReleaseBuffer(int nNewLen = -1);
	TString<T>& Cat(const T *pStr);
	TString<T>& Cat(const T c);
	TString<T>& DiffCat(const T *pStart, const T *pEnd);
	TString<T>& Replace(const T *szFind, const T *szReplaceBy);
	TString<T>& Replace(int nIndex, int nCount, const T *szReplaceBy);
	TString<T> Left(int nCount) const;
	TString<T> Right(int nCount) const;
	TString<T> SubStr(int nIndex, int nCount) const;
	TString<T> ToLower() const;
	void Empty();
	void Free();
	T& operator [] (int nIndex) { _ASSERT(nIndex >= 0 && nIndex <= GetLen()); return pBuf[nIndex]; }
	operator const T*() const { return pBuf; }
	operator T*() { return pBuf; }
	TString<T>& operator=(const T *pStr);
	TString<T>& operator=(const TString<T> &Str) { return *this = Str.pBuf; }
	//	TCString& operator + (const char *pStr)
	//		{_ASSERT(pBuf && pStr); TCString Result(*this); return Result.Cat(pStr);}
	friend TString<T> operator + (const TString<T> &Str1, const T *Str2)
	{
		_ASSERT(Str1.pBuf && Str2); TString<T> Result(Str1); return Result.Cat(Str2);
	}
	/*	friend TCString operator + (const char *Str1, const TCString &Str2)
			{_ASSERT(Str1 && Str2.pBuf); TCString Result(Str1); return Result.Cat(Str2);}*/
	TString<T>& operator+=(const T *pStr) { _ASSERT(pBuf && pStr); return this->Cat(pStr); }
	TString<T>& operator+=(const T c) { _ASSERT(pBuf); return this->Cat(c); }
	int operator == (const T *pStr) const { return (!pBuf || !pStr) ? (pBuf == pStr) : !My_lstrcmp(pBuf, pStr); }
	int operator != (const T *pStr) const { return (!pBuf || !pStr) ? (pBuf != pStr) : My_lstrcmp(pBuf, pStr); }
	int operator < (const T *pStr) const { _ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) > 0; }
	int operator > (const T *pStr) const { _ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) < 0; }
	int operator <= (const T *pStr) const { _ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) >= 0; }
	int operator >= (const T *pStr) const { _ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) <= 0; }
	//	TCString& Format(char *pszFormat, ...);

private:
	void SetBufSize(int nNewBufSize);
	void SetAllocSize(int nNewAllocSize);

	T *pBuf;
	int nBufSize; // current string length + 1 (including 0 at the end)
	int nAllocSize; // allocated memory size
};


typedef TString<wchar_t> TCString;
typedef TString<char> CString;
typedef TString<wchar_t> WCString;

#ifdef CHARARRAY_CONVERT

__inline CHARARRAY WCHAR2ANSI_ARRAY(CHARARRAY &c)
{
	CHARARRAY Result;
	int Len = WideCharToMultiByte(CP_ACP, 0, (wchar_t*)c.GetData(), c.GetSize() / sizeof(wchar_t), NULL, 0, NULL, NULL);
	if (Len) {
		Result.SetAtGrow(Len - 1);
		if (!WideCharToMultiByte(CP_ACP, 0, (wchar_t*)c.GetData(), c.GetSize() / sizeof(wchar_t), Result.GetData(), Len, NULL, NULL)) {
			Result.RemoveAll();
		}
		if (Result.GetSize()) {
			Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
		}
	}
	return Result;
}

__inline CHARARRAY ANSI2WCHAR_ARRAY(CHARARRAY &c)
{
	CHARARRAY Result;
	int Len = MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), NULL, 0);
	if (Len) {
		Result.SetAtGrow(Len * sizeof(wchar_t) - 1);
		if (!MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), (wchar_t*)Result.GetData(), Len)) {
			Result.RemoveAll();
		}
		if (Result.GetSize()) {
			Result.RemoveElem(Result.GetSize() - 1);
			Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
		}
	}
	return Result;
}


__inline CHARARRAY WCHAR2UTF8(WCString Str)
{
	CHARARRAY Result;
	int Len = WideCharToMultiByte(CP_UTF8, 0, Str, -1, NULL, 0, NULL, NULL);
	if (Len) {
		Result.SetAtGrow(Len - 1);
		if (!WideCharToMultiByte(CP_UTF8, 0, Str, -1, Result.GetData(), Len, NULL, NULL)) {
			Result.RemoveAll();
		}
	}
	return Result;
}


#endif // CHARARRAY_CONVERT


#undef db_get_s
CString db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szDefaultValue);
TCString db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szDefaultValue);
int db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv);
TCString DBGetContactSettingAsString(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szDefaultValue); // also converts numeric values to a string

// various string helpers. their return values are valid only while the class is visible
class UTF8Encode
{
public:
	UTF8Encode(const char *str) { p = mir_utf8encode(str); }
	UTF8Encode(const wchar_t *str) { p = mir_utf8encodeW(str); }
	~UTF8Encode() { mir_free(p); }
	operator char*() { return p; }

private:
	char *p;
};

class UTF8DecodeA
{
public:
	UTF8DecodeA(const char *str) { p = mir_strdup(str); mir_utf8decode(p, NULL); }
	~UTF8DecodeA() { mir_free(p); }
	operator char*() { return p; }

private:
	char *p;
};

class UTF8DecodeW
{
public:
	UTF8DecodeW(const char *str) { p = mir_utf8decodeW(str); }
	~UTF8DecodeW() { mir_free(p); }
	operator wchar_t*() { return p; }

private:
	wchar_t *p;
};


#define UTF8Decode UTF8DecodeW


/*class mallocStrA
{
public:
	mallocStrA(int n) { p = (char*)malloc((n + 1) * sizeof(char)); }
	mallocStrA(const char *str) { p = str ? strdup(str) : NULL; }
	~mallocStrA() { if (p) free(p); }
	operator char*() { return p; }

private:
	char *p;
};

class mallocStrW
{
public:
	mallocStrW(int n) { p = (wchar_t*)malloc((n + 1) * sizeof(wchar_t)); }
	mallocStrW(const wchar_t *str) { p = str ? _wcsdup(str) : NULL; }
	~mallocStrW() { if (p) free(p); }
	operator wchar_t*() { return p; }

private:
	wchar_t *p;
};


#define mallocStr mallocStrW

*/