#ifndef KZ_BASE_H
#define KZ_BASE_H

#include <string>
#include "kz_cformat.h"

using namespace std;


inline void replace_all( const string &src, const string &fstr, const string &repstr, string &retstr, size_t off = 0)
{
	size_t	flen = fstr.size();
	size_t	fnd;
	retstr.clear();
	retstr.reserve(src.capacity());
	retstr.assign( src.begin(), src.begin() + off);
	while ( (fnd = src.find( fstr, off)) != string::npos ) {
		retstr += src.substr( off, fnd - off);
		retstr += repstr;
 		off = fnd + flen;
	}
	retstr += src.substr(off);
}


inline void replace_first( const string &src, const string &fstr, const string &repstr, string &retstr, size_t off = 0)
{
	size_t	flen = fstr.size();
	size_t	fnd;
	retstr.clear();
	retstr.reserve(src.capacity());
	retstr.assign( src.begin(), src.begin() + off);
	if ( (fnd = src.find( fstr, off)) != string::npos ) {
		retstr += src.substr( off, fnd - off);
		retstr += repstr;
 		off = fnd + flen;
	}
	retstr += src.substr(off);
}

inline void replace_regex_all( const string &srcstr, const char *fstr, const char *repstr, string &dststr, size_t off = 0)
{
	boost::regex fnd(fstr);
	ostringstream t(ios::out | ios::binary);
	ostream_iterator<char, char> oi(t);
    boost::regex_replace( oi, srcstr.begin() + off, srcstr.end(), fnd, repstr, boost::match_default | boost::format_all);
	dststr.assign( srcstr.begin(), srcstr.begin() + off);
	dststr += t.str();
}

inline void replace_regex_first( const string &srcstr, const char *fstr, const char *repstr, string &dststr, size_t off = 0)
{
	boost::regex fnd(fstr);
	ostringstream t(ios::out | ios::binary);
	ostream_iterator<char, char> oi(t);
    boost::regex_replace( oi, srcstr.begin() + off, srcstr.end(), fnd, repstr, boost::match_default | boost::format_first_only);
	dststr.assign( srcstr.begin(), srcstr.begin() + off);
	dststr += t.str();
}

// utf8からunicodeへの変換（1文字)
inline void utf8_to_unicode( string &src, wchar_t &unicode)
{
	// ロケールの保存と設定
	string::const_iterator i = src.begin();
	wchar_t	wc = 0;
	if ( (0x80 & *i) == 0 ) {
		wc = *i;
	} else if ( (0xe0 & *i) == 0xc0 ) {
		if ( i + 1 < src.end() && (0xc0 & i[1]) == 0x80 ) {
			wc = ((i[0] & 0x1f) << 6) | (i[1] & 0x3f);
			i++;
		}
	} else if ( (0xf0 & *i) == 0xe0 ) {
		if ( i + 2 < src.end() && (0xc0 & i[1]) == 0x80 && (0xc0 & i[2]) == 0x80 ) {
			wc = ((i[0] & 0x0f) << 12) | ((i[1] & 0x3f) << 6) | (i[2] & 0x3f);
			i += 2;
		}	
	}
	unicode = wc;
}

inline void str2json(const string &str, string &value_) {
	value_.push_back('"');
	for ( string::const_iterator i = str.begin(); i < str.end(); i++ ) {
		switch ( *i ) {
			case '"' :
				value_.push_back('\\');
				value_.push_back('"');
				break;
			case '\\' :
				value_.push_back('\\');
				value_.push_back('\\');
				break;
			case '\r' :
				value_.push_back('\\');
				value_.push_back('r');
				break;
			case '\n' :
				value_.push_back('\\');
				value_.push_back('n');
				break;
			default :
				if ( isprint(*i) ) {
					value_.push_back(*i);
				} else if ( *i >= 0x80 ) {
					string utf8;
					int cnt = str.end() - i;
					if ( (*i & 0xe0) == 0xc0 ) {
						if ( cnt > 1 ) {
							utf8.push_back(*i++);
							utf8.push_back(*i);
						}
					} else if ( (*i & 0xf0) == 0xe0 ) {
						if ( cnt > 2 ) {
							utf8.push_back(*i++);
							utf8.push_back(*i++);
							utf8.push_back(*i);
						}
					}
					wchar_t u;
					utf8_to_unicode( utf8, u);
					value_ += cformat("\\u%04x", u);
				} else {
					value_ += cformat("\\u%04x", *i); 
				}
		}
	}
	value_.push_back('"');
}

inline bool revcmp( string &src, const char *dst, size_t len)
{
	if ( src.size() < len ) return false;
	return strcmp( src.c_str() + src.size() - len, dst) == 0;
}

inline bool revcmp3( string &src, const char *dst1, const char *dst2, const char *dst3, size_t len)
{
	if ( src.size() < len ) return false;
	if ( strcmp( src.c_str() + src.size() - len, dst1) == 0 ) return true;
	if ( strcmp( src.c_str() + src.size() - len, dst2) == 0 ) return true;
	if ( strcmp( src.c_str() + src.size() - len, dst3) == 0 ) return true;
	return false;
}

inline long long mypow(long long a, long long n ) {
		if ( n == 0 ) return 1;
		if ( n % 2 ) return a * mypow( a, n - 1);
		long long x = mypow( a, n >> 1);
		return x * x;
	}

inline	bool isprime(long long n ) {
		if ( n == 1 ) return false;
		if ( n == 2 ) return true;
		if ( n % 2 == 0 ) return false;
		for ( long long i = 3; i * i <= n; i += 2 ) {
			if ( n % i == 0 ) return false;
		}
		return true;
	}


inline	long long mygcm(long long a, long long b) {
		if ( a  < b ) { long long t = a; a = b; b = t; }
		while ( b != 0 ) {
			long long ob = b;
			b = a % ob;
			a = ob;
		}
		return a;
	}
	
#endif
