//  algorithm : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 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
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99


#ifndef __CPP_ISTREAM
#define __CPP_ISTREAM

#include<iosfwd>
#include<ios>
#include<ostream>

namespace std {
	template <class charT, class traits>
	class basic_istream : virtual public basic_ios<charT, traits> 
	{
		private:
			streamsize num_last_extracted;
		public:
			typedef typename traits::int_type int_type;
			typedef typename traits::pos_type pos_type;
			typedef typename traits::off_type off_type;
		
			explicit basic_istream(basic_streambuf<charT,traits> *sb) : basic_ios<charT, traits>(sb)
			{
				num_last_extracted = 0;
			}

			virtual ~basic_istream()
			{
			}
			/*						
			class sentry
			{
				typedef traits traits_type;
				bool ok_; // exposition only
				public:
				explicit sentry(basic_istream<charT,traits> &is, bool noskipws = false)
				{
				}
				~sentry()
				{
				}
				
				operator bool() 
				{ 
					return ok_;
				}
 
			}; */

			basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>& (*pf)(basic_istream<charT,traits>&))
			{
				return pf(*this);
			}

			basic_istream<charT,traits>& operator>>(basic_ios<charT,traits>& (*pf)(basic_ios<charT,traits>&))
			{			
				pf(*this);
				return *this;
			}
			
			basic_istream<charT,traits>& operator>>(ios_base& (*pf)(ios_base&))
			{
				pf(*this);
				return *this;
			}

			basic_istream<charT,traits>& operator>>(bool &n)
			{ // TODO
				char c = get();
				if (c == '0')
					n = false;
				else
				if (c == '1')
					n = true;
				else
					unget(); // failed
				return *this;
			}			
						
			basic_istream<charT,traits>& operator>>(short &n)
			{
				long tmp;
				operator>>(tmp);
				n = (short)tmp;
				return *this;
			}
			
			basic_istream<charT,traits>& operator>>(unsigned short &n)
			{
				unsigned long tmp;
				operator>>(tmp);
				n = (unsigned short)tmp;
				return *this;		
			}
			
			basic_istream<charT,traits>& operator>>(int &n)
			{
				long tmp;
				operator>>(tmp);
				n = (int)tmp;
				return *this;							
			}
			
			basic_istream<charT,traits>& operator>>(unsigned int &n)
			{
				unsigned long tmp;
				operator>>(tmp);
				n = (unsigned int)tmp;				
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(long &n)
			{
				bool neg = false;
				ws(*this);				
				int tmp = 0;
				int a = rdbuf()->sbumpc();
				if (a == '-') {
					neg = true;
					a = rdbuf()->sbumpc();
				}
				while ((a>='0' && a <= '9') || 
					   (a>='A' && a <= 'Z'))
				{
					if (a >= 'A') 
						a -= 'A';
					else 
						a -= '0';
						
					tmp = tmp * curfmt.base + a;
					a = rdbuf()->sbumpc();
				}
				n = tmp;
				if (!eof())
					unget();
				if (neg)
					n*=-1;
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(unsigned long &n)
			{
				ws(*this);
				
				int tmp = 0;
				int a = rdbuf()->sbumpc();
				while ((a>='0' && a <= '9') || 
					   (a>='A' && a <= 'Z'))
				{
					if (a >= 'A')
						a -= 'A';
					else 
						a -= '0';
						
					tmp = tmp * curfmt.base + a;
					a = rdbuf()->sbumpc();
				}
				n = tmp;
				if (!eof())
					unget();
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(float &f)
			{
				printf("istream : todo 4\n");
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(double &f)
			{
				printf("istream : todo 5\n");
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(long double &f)
			{
				printf("istream : todo 6\n");
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(void *&p)
			{
				printf("istream : todo 7\n");
				return *this;			
			}
			
			basic_istream<charT,traits>& operator>>(basic_streambuf<charT,traits> *sb)
			{ // TODO : TEST THIS FUNCTION / CORRECT ERRORS
				if (sb == 0)
					setstate(ios_base::failbit);
				charT c;
				while (get(c))
					sb->sputc(c);
				return *this;			
			}
			
			
			streamsize gcount() const
			{
				return num_last_extracted;
			}
			
			
			int_type get()
			{
				if (eof()) {
					setstate(ios_base::failbit);
					return traits::eof();
				}
				int_type i = rdbuf()->sbumpc();
				
				if (i == traits::eof()) {
					setstate(ios_base::eofbit);
					return 0;
				}
				num_last_extracted  = 1;
				return i;
			}

			basic_istream<charT,traits>& get(charT& c)
			{
				c = traits::to_char_type(this->get());
				return *this;
			}
	
			basic_istream<charT,traits>& get(charT* s, streamsize n)
			{
				return 	getline(s, n, widen('\n'));
			}
			
			basic_istream<charT,traits>& get(charT* s, streamsize n, charT delim)
			{// TODO : TEST 
				int i = 0;
				int_type t;
				num_last_extracted = 0;
				do {
					t = get();
					if (t == traits::eof()) {
						setstate(eofbit);
						break;
					}
					if (traits::to_char_type(t) == delim) {
						putback(delim);
						break;
					}
					num_last_extracted++;
					s[i++] = traits::to_char_type(t);
				} while (i < n);
				return *this;
			}

			basic_istream<charT,traits>& get(basic_streambuf<charT,traits> &sb)
			{   // TODO : IS THIS FUNCTION CORRECT ? (ERROR IN MY COPY OF THE STANDARD)
				return get(sb, widen('\n'));
			}

			basic_istream<charT,traits>& get(basic_streambuf<charT,traits> &sb, charT delim)
			{ // TODO : TEST
				try {
					num_last_extracted = 0;
					while (1) {
						int_type t = get();
						if (t == traits::eof())
							break;
						if (traits::to_char_type(t) == delim) {
							putback(delim);
							break;
						}
						num_last_extracted++;
						sb.sputc(t);
					}
					return *this;
				} catch (exception e) {
				 	// NOTHING
				}
			}

			basic_istream<charT,traits>& getline(charT* s, streamsize n)
			{
				return getline(s, n, widen('\n'));
			}
	
			basic_istream<charT,traits>& getline(charT* s, streamsize n, charT delim)
			{
				while(1) {
					int_type t = get();
					if (t == traits::eof()) {
						setstate(eofbit);
						break;
					}
					if (traits::to_char_type(t) == delim) 
						break;
					s[i++] = traits::to_char_type(t);
					if (i >= n) {
						setstate(ios_base::failbit);
						break;
					}
				}
				return *this;
			}

			
			basic_istream<charT,traits>& ignore(streamsize n = 1, int_type delim = traits::eof())
			{
				while(1) {
					int_type t = get();
					if (n-- > 0)
						break;
					if (t == traits::eof()) {
						setstate(eofbit);
						break;
					}
					if (t == delim) 
						break;
				}
		
				return *this;		
			}
			
			int_type peek()
			{
				return good() ? (rdbuf()->sgbetc) : (traits::eof()) ;
			}
			
			basic_istream<charT,traits> &read (charT* s, streamsize n)
			{
				rdbuf()->sgetn(s, n);
				return *this;
			}
			
			streamsize  readsome(charT* s, streamsize n)
			{
				streamsize num = 0;
				if (!good())
					setstate(failbit); 
				else {
					num = read(s, n);
					if (rdbuf()->in_avail()  ==  -1)
						setstate(eofbit);
				}
				return num;
			}
			
			basic_istream<charT,traits>& putback(charT c)
			{
				if (!good()) {
					setstate(failbit); 
					return *this;
				}
				if (rdbuf() == 0)
					setstate(ios_base::badbit);
	
				if (rdbuf()->sputbackc(c) == traits::eof())
					setstate(ios_base::badbit);
				return *this;
			}
			
			basic_istream<charT,traits>& unget()
			{
				if (!good()) {
					setstate(failbit); 
					return *this;
				}
				if (rdbuf() == 0)
					setstate(ios_base::badbit);

				if (rdbuf()->sungetc() == traits::eof()) 
					setstate(ios_base::badbit);

				return *this;
			}
			
			int sync()
			{
				if (rdbuf() == 0)
					return -1;
				if (rdbuf()->pubsync() == -1)
					setstate(ios_base::badbit);
				return 0;
			}
			
			pos_type tellg()
			{
				if (!fail())
					return pos_type(-1);
				return rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
			}

			basic_istream<charT,traits>& seekg(pos_type pos)
			{
				if (!fail())
					rdbuf()->pubseekpos(pos);
				return *this;
			}

			basic_istream<charT,traits>& seekg(off_type off, ios_base::seekdir dir)
			{ 
				if (!fail()) 
					rdbuf()->pubseekoff(off, dir);
				return *this;
			}
	};
	
	template<class charT, class traits>
	basic_istream<charT,traits> &operator>>(basic_istream<charT,traits> &is, charT &x)
	{
		ws(is);
		return is.get(x);
	}
	
	template<class traits>
	basic_istream<char,traits> &operator>>(basic_istream<char,traits> &is, unsigned char &x)
	{
		ws(is);
		return is.get(x);
	}
	
	template<class traits>
	basic_istream<char,traits> &operator>>(basic_istream<char,traits> &is, signed char &x)
	{
		ws(is);
		return is.get(x);
	}

	template<class charT, class traits>
	basic_istream<charT,traits> &operator>>(basic_istream<charT,traits> &is, charT *x)
	{
		ws(is);
		int c;
		c = is.get();
		do {
			*x++=c;
			c = is.get();
		} while (c != traits::eof() && c != widen(' ') && c != widen('\t') && c!= widen('\n'));
		if (!fail())
		return is;
	}

/* is the template not enough ???

	template<class traits>
	basic_istream<char,traits> &operator>>(basic_istream<char,traits> &is, unsigned char *x)
	{
		return is;
	}
	
	template<class traits>
	basic_istream<char,traits> &operator>>(basic_istream<char,traits> &is, signed char *x)
	{
		return is;
	}
*/	
	typedef basic_istream<char>     istream;
	typedef basic_istream<wchar_t> wistream;
	
	template <class charT, class traits>
	basic_istream<charT,traits> &ws(basic_istream<charT,traits> &is)
	{
//		if (is.flags() & ios_base::skipws)
		{
			int c = is.get();
			while (1) {					
				if (c == ' ' || c == '\t' || c == '\n' || c == 0 || c == 13 ) {
					c = is.get();
					if (is.fail())
						break;
				} else {
					is.putback(c);
					break;
				}
			}											
		}
		return is;
	}

	// 27.6.1.5 Template class basic_iostream
	template <class charT, class traits>
	class basic_iostream :	
		public basic_istream<charT,traits>,
		public basic_ostream<charT,traits> 
	{
		public:
			explicit basic_iostream(basic_streambuf<charT,traits>* sb)
			: basic_istream<charT, traits>(sb), basic_ostream<charT, traits>(sb)
			{
			}
			
			virtual ~basic_iostream()
			{
			}
	};
	


}

#endif
