/*	Copyright (C) 2004 Garrett A. Kajmowicz

	This file is part of the uClibc++ Library.

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

	This library 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
	Lesser General Public License for more details.

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

#include <basic_definitions>

#ifndef HEADER_STD_SSTREAM
#define HEADER_STD_SSTREAM 1

#include <iosfwd>
#include <ios>
#include <istream>
#include <ostream>
#include <iostream>
#include <string>

namespace std{

	template <class charT, class traits, class Allocator>
		class basic_stringbuf : public basic_streambuf<charT,traits>
	{
	public:
		typedef charT char_type;
		typedef typename traits::int_type int_type;
		typedef typename traits::pos_type pos_type;
		typedef typename traits::off_type off_type;
		typedef typename Allocator::size_type size_type;

		explicit basic_stringbuf(ios_base::openmode which = ios_base::in | ios_base::out)
			: data(), ielement(0), oelement(0)
		{
			basic_streambuf<charT,traits>::openedFor = which;
		}

		explicit basic_stringbuf(const basic_string<charT,traits,Allocator>& str,
			ios_base::openmode which = ios_base::in | ios_base::out)
			: data(str), ielement(0), oelement(str.length())
		{
			basic_streambuf<charT,traits>::openedFor = which;
		}

		virtual ~basic_stringbuf();

		basic_string<charT,traits,Allocator> str() const{
			return data;
		}

		void str(const basic_string<charT,traits,Allocator>& s){
			data = s;
			ielement = 0;
			oelement = data.length();
		}

	protected:
		virtual int sync(){
			return 0;
		}
		virtual int_type underflow(){
			if(ielement >= data.length()){
				return traits::eof();
			}
			return traits::to_int_type(data[ielement]);
		}

		virtual int_type uflow(){
			int_type retval = underflow();
			if(retval != traits::eof()){
				++ielement;
			}
			return retval;	
		}

		virtual int_type   pbackfail(int_type c = traits::eof()){
			//Error possibilities
			if(ielement == 0){
				return traits::eof();
			}
			if(ielement > data.length()){
				ielement = data.length();
				return traits::eof();
			}
			//eof passed in
			if(traits::eq_int_type(c,traits::eof())==true){
				--ielement;
				return traits::not_eof(c);
			}
			if(traits::eq(traits::to_char_type(c),data[ielement-1]) == true){
				--ielement;
				return c;
			}
			if(basic_streambuf<charT,traits>::openedFor & ios_base::out){
				--ielement;
				data[ielement] = c;
				return c;
			}
			return traits::eof();
		}

		virtual int showmanyc(){
			return data.length() - ielement;
		}
		virtual streamsize xsgetn(char_type* c, streamsize n){
			streamsize i = 0;
			while(ielement < data.length() && i < n ){
				c[i] = data[ielement];
				++i;
				++ielement;
			}
			return i;
		}

		virtual int_type   overflow (int_type c = traits::eof()){
			//Nothing to do
			if(traits::eq_int_type(c,traits::eof())){
				return traits::not_eof(c);
			}

			//Actually add character, if possible
			if(basic_streambuf<charT,traits>::openedFor & ios_base::out){
				if(oelement >= data.length()){
					data.push_back(c);
				}else{
					data[oelement] = c;
				}
				++oelement;
				return c;
			}
			//Not possible
			return traits::eof();
		}

		virtual  basic_streambuf<charT,traits>* setbuf(charT*, streamsize){
			//This function does nothing
			return this;
		}

		virtual streamsize xsputn(const char_type* s, streamsize n){
			streamsize alen = n;
			streamsize rlen = data.length() - oelement;
			if(alen < rlen){
				rlen = alen;
			}
			if( rlen > 0 ){
				data.replace(oelement, rlen, s);
				oelement += rlen;
				alen -= rlen;
			}
			if(alen > 0){
				data.append(s + rlen, alen);
				oelement += alen;
			}
			return n;
		}

		virtual pos_type seekoff(off_type off, ios_base::seekdir way,
			ios_base::openmode which = ios_base::in | ios_base::out)
		{
			//Test for invalid option
			if( (which & ios_base::in) && (which & ios_base::out) && (way == ios_base::cur)){
				return -1;
			}

			//Calculate new location
			size_type newpos = 0;

			if(way == ios_base::beg){
				newpos = off;
			}else if(way == ios_base::cur){
				if(which & ios_base::out){
					newpos = data.length() + off;
				}
				if(which & ios_base::in){
					newpos = ielement + off;
				}
				
			}else{
				newpos = data.length() + off;
			}

			//Test for error conditions
			if(newpos > data.length()){
				return -1;
			}

			//Shuffle pointers

			if(which & ios_base::in){
				ielement = newpos;
			}
			if(which & ios_base::out){
				data.resize(newpos);
				if(ielement > data.length()){
					ielement = data.length();
				}
			}

			return newpos;
		}
			
		virtual pos_type seekpos(pos_type sp, 
			ios_base::openmode which = ios_base::in | ios_base::out)
		{
			return seekoff(sp, ios_base::beg, which);
		}

		basic_string<charT,traits,Allocator> data;
		size_type ielement;
		size_type oelement;
	};


	template <class charT, class traits, class Allocator> basic_stringbuf<charT, traits, Allocator>::~basic_stringbuf(){ }

#ifdef __UCLIBCXX_EXPAND_STRING_CHAR__


#endif


	template <class charT, class traits, class Allocator> class basic_istringstream
		: public basic_istream<charT,traits>
	{
	public:
		typedef charT char_type;
		typedef typename traits::int_type int_type;
		typedef typename traits::pos_type pos_type;
		typedef typename traits::off_type off_type;


		explicit basic_istringstream(ios_base::openmode m = ios_base::in) 
			: basic_istream<charT,traits>(&sb), sb(m) {  }
		explicit basic_istringstream( const basic_string<charT,traits,Allocator>& str, 
			ios_base::openmode which = ios_base::in) 
			: basic_istream<charT,traits>(&sb), sb(str, which) {  }

		basic_stringbuf<charT,traits,Allocator>* rdbuf() const{
			return &sb;
		}
		basic_string<charT,traits,Allocator> str() const{
			return sb.str();
		}
		void str(const basic_string<charT,traits,Allocator>& s){
			sb.str(s);
			basic_istream<charT,traits>::clear();
		}
	private:
		basic_stringbuf<charT,traits,Allocator> sb;
	};


	template <class charT, class traits, class Allocator>class basic_ostringstream
		: public basic_ostream<charT,traits>
	{
	public:

		typedef charT char_type;
		typedef typename traits::int_type int_type;
		typedef typename traits::pos_type pos_type;
		typedef typename traits::off_type off_type;

		explicit basic_ostringstream(ios_base::openmode m = ios_base::out)
			: basic_ostream<charT,traits>(&sb), sb(m) {  }
		explicit basic_ostringstream(const basic_string<charT,traits,Allocator>& str, 
			ios_base::openmode which = ios_base::out)
			: basic_ostream<charT,traits>(&sb), sb(str, which) {  }
		virtual ~basic_ostringstream() {  }

		basic_stringbuf<charT,traits,Allocator>* rdbuf() const{
			return &sb;
		}
		basic_string<charT,traits,Allocator> str() const{
			return sb.str();
		}
		void str(const basic_string<charT,traits,Allocator>& s){
			sb.str(s);
			basic_ostream<charT,traits>::clear();
		}
	private:
		basic_stringbuf<charT,traits,Allocator> sb;
	};


	template <class charT, class traits, class Allocator> class basic_stringstream
		 : public basic_iostream<charT,traits>
	{
	public:

		typedef charT char_type;
		typedef typename traits::int_type int_type;
		typedef typename traits::pos_type pos_type;
		typedef typename traits::off_type off_type;

		explicit basic_stringstream(ios_base::openmode which = ios_base::out|ios_base::in)
			: basic_iostream<charT,traits>(&sb), sb(which) {  }
		explicit basic_stringstream(const basic_string<charT,traits,Allocator>& str,
			ios_base::openmode which = ios_base::out|ios_base::in)
			: basic_iostream<charT,traits>(&sb), sb(str, which) {  }
		virtual ~basic_stringstream();

		basic_stringbuf<charT,traits,Allocator>* rdbuf(){
			return &sb;
		}
		basic_string<charT,traits,Allocator> str() const{
			return sb.str();
		}
		void str(const basic_string<charT,traits,Allocator>& s){
			sb.str(s);
			basic_iostream<charT,traits>::clear();
		}
	private:
		basic_stringbuf<charT, traits> sb;
	};

	template <class charT, class traits, class Allocator> 
		basic_stringstream<charT, traits, Allocator>::~basic_stringstream() { }


#ifdef __UCLIBCXX_EXPAND_STRING_CHAR__

#endif


}


#endif
