/*! \file pichar.h
 * \brief Unicode char
*/
/*
    PIP - Platform Independent Primitives
    Unicode char
    Copyright (C) 2015  Ivan Pelipenko peri4ko@gmail.com

    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 3 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, see <http://www.gnu.org/licenses/>.
*/

#include "pichar.h"
#ifdef PIP_ICU
#  include "unicode/ucnv.h"
char * __syslocname__ = 0;
char * __sysoemname__ = 0;
#endif


/*! \class PIChar
 * \brief Unicode char
 * \details This class is wrapper around \c "uint".
 * There are many contructors and information functions
 */


PIChar::PIChar(const char * c) {
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open(__syslocname__, &e);
	if (cc) {
		UChar uc;
		e = (UErrorCode)0;
		ucnv_toUChars(cc, &uc, 1, c, 4, &e);
		ucnv_close(cc);
		ch = uc;
		return;
	}
#endif
	ch = *reinterpret_cast<const int * >(c);
}


PIChar PIChar::fromConsole(char c) {
	PIChar ret;
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open(__sysoemname__, &e);
	if (cc) {
		UChar uc;
		e = (UErrorCode)0;
		ucnv_toUChars(cc, &uc, 1, &c, 1, &e);
		ucnv_close(cc);
		ret.ch = uc;
		return ret;
	}
#endif
	ret.ch = c;
	return ret;
}


PIChar PIChar::fromSystem(char c) {
	PIChar ret;
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open(__syslocname__, &e);
	if (cc) {
		UChar uc;
		e = (UErrorCode)0;
		ucnv_toUChars(cc, &uc, 1, &c, 1, &e);
		ucnv_close(cc);
		ret.ch = uc;
		return ret;
	}
#endif
	ret.ch = c;
	return ret;
}


PIChar PIChar::fromUTF8(const char * c) {
	PIChar ret;
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open("UTF-8", &e);
	if (cc) {
		UChar uc;
		e = (UErrorCode)0;
		ucnv_toUChars(cc, &uc, 1, c, 8, &e);
		ucnv_close(cc);
		ret.ch = uc;
		return ret;
	}
#endif
	ret.ch = *(ushort*)c;
	return ret;
}


bool PIChar::operator ==(const PIChar & o) const {
	return ch == o.ch;
}


bool PIChar::operator >(const PIChar & o) const {
	return
#ifdef PIP_ICU
			u_strCompare((const UChar*)&(ch), 1, (const UChar*)&(o.ch), 1, FALSE) > 0;
#else
			strcmp(toCharPtr(), o.toCharPtr()) > 0;
#endif
}


bool PIChar::operator <(const PIChar & o) const {
	return
#ifdef PIP_ICU
			u_strCompare((const UChar*)&(ch), 1, (const UChar*)&(o.ch), 1, FALSE) < 0;
#else
			strcmp(toCharPtr(), o.toCharPtr()) < 0;
#endif
}


bool PIChar::operator >=(const PIChar & o) const {
	return
#ifdef PIP_ICU
			u_strCompare((const UChar*)&(ch), 1, (const UChar*)&(o.ch), 1, FALSE) >= 0;
#else
			strcmp(toCharPtr(), o.toCharPtr()) >= 0;
#endif
}


bool PIChar::operator <=(const PIChar & o) const {
	return
#ifdef PIP_ICU
			u_strCompare((const UChar*)&(ch), 1, (const UChar*)&(o.ch), 1, FALSE) <= 0;
#else
			strcmp(toCharPtr(), o.toCharPtr()) <= 0;
#endif
}


bool PIChar::isDigit() const {
	return isdigit(ch) != 0;
}


bool PIChar::isHex() const {
	return isxdigit(ch) != 0;
}


bool PIChar::isGraphical() const {
	return isgraph(ch) != 0;
}


bool PIChar::isControl() const {
	return iscntrl(ch) != 0;
}


bool PIChar::isLower() const {
	return islower(ch) != 0;
}


bool PIChar::isUpper() const {
	return isupper(ch) != 0;
}


bool PIChar::isPrint() const {
	return isprint(ch) != 0;
}


bool PIChar::isSpace() const {
	return isspace(ch) != 0;
}


bool PIChar::isAlpha() const {
	return isalpha(ch) != 0;
}


bool PIChar::isAscii() const {
	return isascii(ch) != 0;
}


const wchar_t * PIChar::toWCharPtr() const {
	return reinterpret_cast<const wchar_t * >(&ch);
}


const char * PIChar::toCharPtr() const {
	return reinterpret_cast<const char * >(&ch);
}


wchar_t PIChar::toWChar() const {
	return wchar_t(ch);
}


char PIChar::toConcole1Byte() const {
	if (ch < 0x80) return ch;
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open(__sysoemname__, &e);
	if (cc) {
		char uc[8];
		e = (UErrorCode)0;
		ucnv_fromUChars(cc, uc, 8, (const UChar*)(&ch), 1, &e);
		ucnv_close(cc);
		return uc[0];
	}
#endif
	return toAscii();
}


PIChar PIChar::toUpper() const {
#ifdef PIP_ICU
	UChar c(0);
	UErrorCode e((UErrorCode)0);
	u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
	return PIChar(c);
#else
	return PIChar(toupper(ch));
#endif
}


PIChar PIChar::toLower() const {
#ifdef PIP_ICU
	UChar c(0);
	UErrorCode e((UErrorCode)0);
	u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
	return PIChar(c);
#else
	return PIChar(tolower(ch));
#endif
}




std::ostream & operator <<(std::ostream & s, const PIChar & v) {
	s << v.toCharPtr();
	return s;
}


PICout operator <<(PICout s, const PIChar & v) {
	s.space();
	s.setControl(0, true);
#ifdef PIP_ICU
	UErrorCode e((UErrorCode)0);
	UConverter * cc = ucnv_open(PICout::isBufferActive() ? __syslocname__ : __sysoemname__, &e);
	if (cc) {
		char uc[8];
		memset(uc, 0, 8);
		e = (UErrorCode)0;
		ucnv_fromUChars(cc, uc, 8, (const UChar*)(&v.ch), 1, &e);
		ucnv_close(cc);
		s << uc;
	} else
#endif
	s << v.toCharPtr();
	s.restoreControl();
	return s;
}
