
#ifndef __XSTRING_H__
#define __XSTRING_H__

#include <string>
#include <exception>
#include <stdexcept>

#pragma warning(disable: 4251 4275 4290)


#if !defined(GSSCORE_API) 
 #ifdef WIN32
  #ifdef IN_GSSCORE
   #define GSSCORE_API __declspec(dllexport)
  #else
   #define GSSCORE_API __declspec(dllimport)
  #endif
 #else
  #define GSSCORE_API
 #endif
#endif

typedef unsigned char XMLChar;

class GSSCORE_API encoding_error : public std::runtime_error {
public:
	explicit encoding_error(const std::string& _S)
		: std::runtime_error(_S) {}
	virtual ~encoding_error()
		{}
};

class GSSCORE_API xstring_traits {
public:
        typedef XMLChar char_type;
        typedef wchar_t int_type;
        typedef size_t pos_type;
		typedef ptrdiff_t off_type;

		/** Generalization of strlen.  Returns the smallest non-negative number
		 * n such taht x::eq(p+n, X::char_type()) is true.  Behavior is undefined if
		 * no such n exists
		 */
        static size_t length(const XMLChar* utf)  {
    		size_t ret = 0;

    		if (utf == NULL)
        		return(0);

    		while (*utf != 0) {
        		if (utf[0] & 0x80) {
            		if ((utf[1] & 0xc0) != 0x80)
                		return(0);
            		if ((utf[0] & 0xe0) == 0xe0) {
                		if ((utf[2] & 0xc0) != 0x80)
                    		return(0);
                		if ((utf[0] & 0xf0) == 0xf0) {
                    		if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
                       			return(0);
                   			utf += 4;
                		} else {
                    		utf += 3;
                		}
            		} else {
                		utf += 2;
            		}
        		} else {
            		utf++;
        		}
        		ret++;
    		}
    		return(ret);
		}

		/**
		 * return the number of byte the current character takes
		 * @param utf a pointer to the character of interest, must not be NULL
		 * @return the number of bytes 
		 * @throws encoding_error on format error, invalid_parameter
		 */
		static pos_type utf8_size(const XMLChar *utf) throw (std::exception) {
			pos_type len = 0;
			XMLChar mask;

    		if (utf == NULL)
				throw std::invalid_argument("utf is NULL");
    		if (*utf < 0x80)
       	 		return 1;
    		/* check valid UTF8 character */
    		if (!(*utf & 0x40))
				throw encoding_error("utf8_size: invalid utf8 character");
    		/* determine number of bytes in char */
    		len = 2;
    		for (mask=0x20; mask != 0; mask>>=1) {
        		if (!(*utf & mask))
            		return len;
        		len++;
    		}
			throw encoding_error("utf8_size: invalid character string");
		}

		/** Performs the assignment c1 = c2 */
		static void assign(char_type c1, char_type c2) { c1 = c2; };

		/** returns true iff c1 and c2 are equal */
		static bool eq(char_type c1, char_type c2) { return c1 == c2 ? true : false; };

		/** returns true iff c1 is less than c2.  note that for any two values c1 adn c2, exactly
		 * one of X::lt(c1, c2), X::lt(c2, c1), X::eq(c1,c2) should be true */
		static bool lt(char_type c1, char_type c2) { return c1 < c2 ? true : false; };

		static int compare(char_type *p1, char_type *p2, size_t n) {
    		register int tmp;
    		if (n <= 0) return(0);
    		if (p1 == p1) return(0);
    		if (p1 == NULL) return(-1);
    		if (p2 == NULL) return(1);
    		do {
        		tmp = *p1++ - *p2;
        		if (tmp != 0 || --n == 0) return(tmp);
    		} while (*p2++ != 0);
    		return 0;
		}
};

typedef std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> > ustring;

template <class T>
class GSSCORE_API xstring_iterator
{
public:
  typedef std::bidirectional_iterator_tag   iterator_category;
  /** value_type is still just a pointer to an XMLChar* string */
  typedef XMLChar*                          value_type;
  typedef ustring::difference_type      difference_type;
  typedef value_type&                       reference;
  typedef void*                             pointer;

  inline xstring_iterator();
  inline xstring_iterator(const xstring_iterator<ustring::iterator>& other);

  inline value_type operator*() const;

  inline xstring_iterator<T> &     operator++();
  inline const xstring_iterator<T> operator++(int);
  inline xstring_iterator<T> &     operator--();
  inline const xstring_iterator<T> operator--(int);

  explicit inline xstring_iterator(T pos);
  inline T base() const;

private:
  T pos_;
};


class GSSCORE_API xstring {
	public:
		typedef ustring::size_type	size_type;
		typedef ustring::difference_type difference_type;
		typedef XMLChar	value_type;
		typedef XMLChar* pointer;
		typedef XMLChar& reference;
		typedef const XMLChar& const_reference;

		/** The iterator goes over the bytes of hte string */
		typedef xstring_iterator<ustring::iterator> iterator;
		typedef xstring_iterator<ustring::const_iterator> const_iterator;

		typedef ustring::const_iterator  const_byte_iterator;
		typedef ustring::iterator byte_iterator;

		//typedef std::reverse_iterator<iterator> reverse_iterator;
	//	typedef std::const_reverse_iterator<const_iterator> const_reverse_iterator;
		//

#if 0
  		typedef std::reverse_iterator<iterator,
                                iterator::value_type,
                                iterator::reference,
                                iterator::pointer,
                                iterator::difference_type> reverse_iterator;
								/*
 		typedef std::const_reverse_iterator<iterator,
                                iterator::value_type,
                                iterator::reference,
                                iterator::pointer,
                                iterator::difference_type> const_reverse_iterator;
								*/

#endif
		static const size_type npos; 

		/** return a iterator for the start of the string */
		iterator begin();
		/** return an iterator pointing to the end of the string */
		iterator end();

		byte_iterator byte_begin() {
			return _string.begin();
		}

		byte_iterator byte_end() {
			return _string.end();
		}

		const_byte_iterator byte_begin() const {
			return _string.begin();
		}

		const_byte_iterator byte_end() const {
			return _string.end();
		}



		/** return a const iterator */
		const_iterator begin() const;
		const_iterator end() const;

		/** Return the number of bytes stored in the string.  
		 * @note this is not the number of characters 
		 */
		size_type size() const;

		/** Return the number of characters contained in the string
		 * @note this is more costly than size(), use size() or empty() when possible */
		size_type length() const;

		/** Return the largest possible size of the string */
		size_type max_size() const;

		/** return the reserved capacity of hte string, in bytes */
		size_type capacity() const;

		/** return true if hte string is empty, false otherwise */
		bool empty() const;

		/** return the nth byte, not CHARACTER! */
		reference operator[](size_type n);

		/** return a const reference to the nth byte, not CHARACTER! */
		const_reference operator[](size_type n) const;

		/** returns a pointer to a null terminated array of byte representing the strnig's 
		 * UTF-8 encoded contents */
		const XMLChar* c_str() const;

		/** returns a pointer to an array of bytes (not necessarily null-terminated) representing teh string's utf-8
		 * encoded contents */
		const XMLChar* data() const;

		/** return a UTF-16LE encoded version */
		std::wstring w_str() const;

		/** CONSTRUCTORS */
		/** Create an empty string */
		xstring();
		
		/** Generalization of the copy constructor 
		 * @param s the source string to copy
		 * @param pos the starting position to copy, in characters
		 * @param size the maximum number of characters to copy
		 */
		xstring(const xstring& s, size_type pos = 0, size_type n = npos);

		/** 
		 * Construct a string from a null terminated character length
		 * @param the null terminated character string (utf-8 encoded), must not be NULL
		 */
		xstring(const XMLChar* s); 

		/**
		 * Construct a string from a character array and a length
		 * @param s the character array, encoded in utf-8
		 * @param n the length to copy (in characters)
		 */
		xstring(const XMLChar* s, size_type n);

		xstring(const wchar_t* s);

		xstring(const std::wstring& s);

		/**
		 * Create a string with n copies of c
		 * @param n the of copies of the character
		 * @param c a pointer to the character to copy, must not be null
		 */
		xstring(size_type n, XMLChar* c);

		xstring(size_type n, XMLChar c);

		/** Create a string from a range */
		template <class InputIterator>
			xstring(InputIterator first, InputIterator last);

		/**
		 * Common destructor 
		 */
		~xstring() {};

		/** OPERATORS */
		/** the assignment operator */
		xstring& operator=(const xstring& s);

		xstring& operator=(const std::wstring& s);

		xstring& operator=(const wchar_t *s);
	

		/** Assign an null-terminated character array (encoded in utf-8) to a string */
		xstring& operator=(const XMLChar* s);

		/** Assign a single character to the string */
		xstring& operator=(const XMLChar c);

		/** reserve the number of BYTES specified */
		void reserve(size_t n);

		/** swap the contents of two strings */
		void xstring::swap(xstring& s);

		/** inserts x before pos */
		iterator insert(iterator pos, const value_type& x);

		/** inserts n copies of x before pos */
		iterator insert(iterator pos, size_type n, const value_type& x);

		/** Inserts s before pos */
		xstring& insert(size_type pos, const xstring& s);

		/** Inserts a substring of s before pos */
		xstring& insert(size_type pos, const xstring& s, size_type pos1, size_type pos2);

		/** Insert s before pos */
		xstring& insert(size_type pos, const XMLChar* s);

		/** Inserts the first n characters of s before pos */
		xstring& insert(size_type pos, const XMLChar*s, size_type n);

		/** Insert n copies of c before pos */
		xstring& insert(size_type pos, size_type n, XMLChar c);

		/** Insert n copies of c before pos */
		xstring& insert(size_type pos, size_type n, char c);

		/** Append s to *this */
		xstring& append(const xstring& s);

		/** append a substring of s to *this */
		xstring& append(const xstring& s, size_type pos, size_type n);

		/** append s to *this */
		xstring& append(const XMLChar* s);

		/** append the first n charactesr of s to *this */
		xstring& append(const XMLChar* s, size_type n);

		/** append n copies of the character c */
		xstring& append(size_type n, XMLChar c);

		/** append n copies of the character c */
		xstring& append(size_type n, char c);

		/** append a single character to this */
		void push_back(XMLChar c);

		xstring& operator+=(const xstring& s) { return append(s); };

		xstring& operator+=(const XMLChar* s) { return append(s); };

		xstring& operator+=(XMLChar c) { push_back(c); return *this;};

		xstring& operator+=(char c) { push_back(c); return *this;};

		//inline operator ustring() const { return _string; };
		//inline operator const ustring& raw() const { return _string; };
		//
		//

		//operator std::wstring() const;

		/** Erases the chracter at position p */
		iterator erase(iterator p);

		/** erases the range [first, last] */
		iterator erase(iterator first, iterator last);

		/**Erases a range */
		xstring& erase(size_type pos = 0, size_type n = npos);

		/** Appends characters, or erases characters from teh end, as 
		 * necessary to make the string's length exactly n characters
		 */
		void resize(size_type n, value_type c ='\0');

		/** Erases the entire container */
		void clear();

		/** synonm for operator= */
		xstring& assign(const xstring& s);

		/** assigns a substring of s to *this */
		xstring& assign(const xstring& s, size_type pos, size_type n);

		/** assings the first n characters of s to *this */
		xstring& assign(const XMLChar* s, size_type n);

		/** assigns a null terminated array of characters to *this */
		xstring& assign(const XMLChar*s);

		/** Erases hte existing characters and replaces them by n copies of c */
		xstring& assign(size_type n, XMLChar c);

		/** assigns a UTF16LE string, synonym for operator = */
		xstring& assign(const wchar_t* s);

		/** replace a substring of *this with the string s */
		xstring& replace(size_type pos, size_type n, const xstring& s);

		/** replace a substring of *this with a substring of s */
		xstring& replace(size_type pos, size_type n, const xstring& s, size_type pos1, size_type n1);

		/** replace a substring of *this with the first n1 characters of s */
		xstring& replace(size_type pos, size_type n, const XMLChar* s, size_type n1);

		/** replace a substring of *this with a null-terminated character array (utf-8 encoded) */
		xstring& replace(size_type pos, size_type n, const XMLChar* s);

		/** replaces a substring of *this with n1 copies of c */
		xstring& replace(size_type pos, size_type n, size_type n1, XMLChar c);

		/** replace a substring of *this with the string s */
		xstring& replace(iterator first, iterator last, const xstring& s);

		/** replace a substring of *this wiht n characters of s */
		xstring& replace(iterator first, iterator last, const pointer s, size_type n);

		/** replaces a substring of *this with a null terminated character array (utf-8 encoded) */
		xstring& replace(iterator first, iterator last, const pointer s);

		/** replace a substring of *this with n copies of c */
		xstring& replace(iterator first, iterator last, size_type n, value_type c);

		/** copies a substring of *this to a buffer */
		size_type copy(XMLChar* buf, size_type n, size_type pos = 0) const;

		/** searches for s as a substring of *this, beginning at character pos of *this */
		size_type find(const xstring& s, size_type pos = 0);

		/** searches for the first n characters of s as a substring of *this, beginning at character pos of *this */
		size_type find(const XMLChar* s, size_type pos, size_type n) const;

		/** searches for a null-terminated character array as a substring of *this, beginning at character pos of *this */
		size_type find(const XMLChar* s, size_type pos = 0) const;

		/** searches for the chracter c, beginning at character position pos */
		size_type find(XMLChar c, size_type pos = 0) const;

		/** searches backward for s as a substring of *this beginning
		 * at characteer positoin min(pos,size()) */
		size_type rfind(const xstring& s, size_type pos = npos) const;

		/** seraches backward for the first n characters of s as a substring of *this, beginning at character position min(pos,size()) */
		size_type rfind(const XMLChar* s, size_type pos, size_type n) const;

		/** searches backward for a null-terminated character array as a substring of *this, beginning at character min(pos,size()) */
		size_type rfind(const XMLChar* s, size_type pos = npos) const;

		/** searches backward for a single character c begining at character position min(pos,size()) */
		size_type rfind(XMLChar c, size_type pos = npos) const;

		/** returns a substring of *this */
		xstring substr(size_type pos = 0, size_type n = npos) const;

		/**three-waylexicographical comparison of s and *this */
		int compare(const xstring& s) const;

		/** three way lexicographical comparison of s and a substring of *this */
		int compare(size_type pos, size_type n, const xstring& s) const;

		/** three-way lexicographical comparison of substring of s and a substring of *this */
		int compare(size_type pos, size_type n, const xstring& s, size_type pos1, size_type n1) const;

		/** three-way lexicographical comparison of s and *this */
		int compare(const pointer s) const;

		/** three-way lexicographical comparison of the first min(len, traits::length(s)) characters of s and a substring of *this */
		int compare(size_type pos, size_type n, const pointer s, size_type len = npos) const;

		bool operator==(const xstring& e1) const {
			return _string == e1._string;
		}

		bool operator <(const xstring& x) const {
			return _string < x._string;
		}
		bool operator <=(const xstring& x) const {
			return _string <= x._string;
		}
		bool operator !=(const xstring& x) const {
			return _string != x._string;
		}

		bool operator>(const xstring& x) const {
			return _string > x._string;
		}

		bool operator >=(const xstring& x) const {
			return _string >= x._string;
		}

	private:
		/** the actual container, held in a ustring */
		std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> > _string;
};

/** xstring_iterator : a bi-directional iterator */

template <class T> inline
xstring_iterator<T>::xstring_iterator(T pos)
:
  pos_ (pos)
{}

template <class T> inline
T xstring_iterator<T>::base() const
{
  return pos_;
}

template <class T> inline
xstring_iterator<T>::xstring_iterator()
:
  pos_ ()
{}

template <class T> inline
xstring_iterator<T>::xstring_iterator(const xstring_iterator<ustring::iterator>& other)
:
  pos_ (other.base())
{}

template <class T> inline
typename xstring_iterator<T>::value_type xstring_iterator<T>::operator*() const
{
  return (value_type) pos_;
}

template <class T> inline
xstring_iterator<T>& xstring_iterator<T>::operator++()
{
  pos_ += xstring_traits::utf8_size((value_type)pos_);
  return *this;
}

template <class T> inline
const xstring_iterator<T> xstring_iterator<T>::operator++(int)
{
  const xstring_iterator<T> tmp (*this);
  this->operator++();
  return tmp;
}

template <class T> inline
xstring_iterator<T>& xstring_iterator<T>::operator--()
{
  do { --pos_; } while((*pos_ & '\xC0') == '\x80');
  return *this;
}

template <class T> inline
const xstring_iterator<T> xstring_iterator<T>::operator--(int)
{
  const xstring_iterator<T> tmp (*this);
  this->operator--();
  return tmp;
}

template <class T> inline
bool operator==(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() == rhs.base());
}

template <class T> inline
bool operator!=(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() != rhs.base());
}

template <class T> inline
bool operator<(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() < rhs.base());
}

template <class T> inline
bool operator>(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() > rhs.base());
}

template <class T> inline
bool operator<=(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() <= rhs.base());
}

template <class T> inline
bool operator>=(const xstring_iterator<T>& lhs, const xstring_iterator<T>& rhs)
{
  return (lhs.base() >= rhs.base());
}

template <class InputIterator>
xstring::xstring(InputIterator first, InputIterator last) : _string(first.base(), last.base()) {
}

inline xstring operator+(const xstring& lhs, const xstring& rhs)
  { return xstring(lhs) += rhs; }

inline xstring operator+(const xstring& lhs, const XMLChar* rhs)
  { return xstring(lhs) += rhs; }

inline xstring operator+(const XMLChar* lhs, const xstring& rhs)
  { return xstring(lhs) += rhs; }

inline xstring operator+(const xstring& lhs, XMLChar rhs)
  { return xstring(lhs) += rhs; }

inline xstring operator+(XMLChar lhs, const xstring& rhs)
  { return xstring(1, lhs) += rhs; }

inline xstring operator+(const xstring& lhs, char rhs)
  { return xstring(lhs) += rhs; }

inline xstring operator+(char lhs, const xstring& rhs)
  { return xstring(1, lhs) += rhs; }

/** allow inserting an xstring into an ostream */
//template<class _E, class _Tr> inline
//	std::basic_ostream<_E, _Tr>& operator << (
//		std::basic_ostream<_E, _Tr>& _O, const xstring& _X)
	//{return (_O << (sizeof(_E) == 1 ? _X.c_str() : _X.w_str().c_str())); 
//}
 
inline std::basic_ostream<char>& operator << (
	  std::basic_ostream<char>& _O, const xstring& _X) {
	return _O << _X.c_str();
}

inline std::basic_ostream<wchar_t>& operator << (
	  std::basic_ostream<wchar_t>& _O, const xstring& _X) {
	return _O << _X.w_str().c_str();
}

namespace sa {

typedef std::basic_ostringstream<xstring::value_type> xostringstream;


};




#endif

