//  ios : 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_IOS
#define __CPP_IOS

#include<cstddef>
#include<new>

#include <iosfwd>
#include <cstdlib>
#include <exception>

#define locale int

namespace std {
	
	template <class stateT> 
	class fpos
	{
		public:
			fpos(stateT t) : st(t)
			{
			}
			stateT state() const
			{
				return st;
			}
			void state(stateT t)
			{
				st = t;
			}
		private:
			stateT st;
	};

	// global format
	// don't use this 
	typedef struct format {
		int flags;
		int state;
		int mode;
		int base, fill, prec, width;
	};
	static format curfmt = {4096, 0, 0, 10, ' ', 0 ,0};

	// 27.4.2 class ios_base
	class ios_base
	{
		public:
			class failure : public exception 
			{
				public:
					explicit failure(const char *msg) 
					{
						m = msg;
					}
					
					virtual ~failure()
					{
					}
					
					virtual const char* what() const
					{
						return m;						
					}
				private:
					const char *m;
			};
			
			typedef int fmtflags;
			typedef int iostate;
			typedef int openmode;
			typedef int seekdir;

			static const fmtflags boolalpha   =     1;
			static const fmtflags dec         =     2;
			static const fmtflags fixed       =     4;
			static const fmtflags hex         =     8;
			static const fmtflags internal    =    16;
			static const fmtflags left        =    32;
			static const fmtflags oct         =    64;
			static const fmtflags right       =   128;
			static const fmtflags scientific  =   256;
			static const fmtflags showbase    =   512;
			static const fmtflags showpoint   =  1024;
			static const fmtflags showpos     =  2048;
			static const fmtflags skipws      =  4096;
			static const fmtflags unitbuf     =  8192;
			static const fmtflags uppercase   = 16384;
			static const fmtflags adjustfield = 32768; 
			static const fmtflags basefield   = 65536;
			static const fmtflags floatfield  = 65536*2;
			
			// indicates a loss of integrity in an input or output sequence
			static const iostate badbit  = 1; 
			// indicates that an input operation reached the end of an input sequence
			static const iostate eofbit  = 2; 
			// indicates that an input operation failed to read the expected characters, 
			// or that an output operation failed to generate the desired characters.
			static const iostate failbit = 4; 
			static const iostate goodbit = 0;
	
			static const openmode app    =  1; // seek to end before each write
			static const openmode ate    =  2; // open and seek to end immediately after opening
			static const openmode binary =  4; // perform input and output in binary mode
			static const openmode in     =  8; // open for input
			static const openmode out    = 16; // open for output
			static const openmode trunc  = 32; // truncate an existing stream when opening
			
			static const seekdir beg = 1; // request a seek relative to the beginning of the stream
			static const seekdir cur = 2; // request a seek relative to the current position within the sequence
			static const seekdir end = 4; // request a seek relative to the current end of the sequence
			
			class Init
			{
				public:
					Init()
					{
						init_cnt++;
					}					
					~Init()
					{
						init_cnt--;
					}
				private:
 					static int init_cnt;
			};

			// 27.4.2.2 fmtflags state:
			fmtflags flags() const
			{
				return curfmt.flags;
			}
			
			fmtflags flags(fmtflags fmtfl)
			{
				return flags()&fmtfl;
			}
			
			fmtflags setf(fmtflags fmtfl)
			{
				fmtflags tmp = flags();
				
				if (fmtfl & ios_base::hex)
					curfmt.base = 16;
				if (fmtfl & ios_base::oct)
					curfmt.base = 8;
				if (fmtfl & ios_base::dec)
					curfmt.base = 10;
				curfmt.flags = fmtfl;
				
				return tmp;				
			}
				
			fmtflags setf(fmtflags fmtfl, fmtflags mask)
			{
				unsetf(mask);
				setf(fmtfl & mask);
				return curfmt.flags;
			}
			
			void unsetf(fmtflags mask)
			{			
				curfmt.flags &= ~mask;
				
				if (flags() & ios_base::hex)
					curfmt.base=16;
				if (flags() & ios_base::oct)
					curfmt.base=8;
				if (flags() & ios_base::dec)
					curfmt.base=10;				
			}
			
			
			streamsize precision() const
			{
				return curfmt.prec;
			}
			
			streamsize precision(streamsize prec)
			{
				streamsize tmp = curfmt.prec;
				curfmt.prec = prec;
				return tmp;
			}
			
			streamsize width() const
			{
				return curfmt.width;
			}
			
			streamsize width(streamsize wide)
			{
				streamsize tmp = curfmt.width;
				curfmt.width = wide;				
				return tmp;
			}
			
			// 27.4.2.3 locales:
			locale imbue(const locale &loc)
			{
				locale tmp = getloc();
				curloc = loc;
				return tmp;
			}

			locale getloc() const
			{
				return curloc;
			}
			
			// 27.4.2.5 storage:
			static int xalloc()
			{
				return index++;			
			}
			
			long &iword(int index)
			{
//				return (long)this->index; // TODO
			}

			void *&pword(int index)
			{ // TODO
/*				static int old_index = 0;
				if (parray == NULL || index > old_index) {
					void** tmp = (void **)new void*[index];				
					memcpy(tmp, parray, old_index * sizeof(void*));
					delete parray;
					parray = tmp;
				}*/
				return parray[index];
			}
			
			~ios_base()
			{
			}
			
			// 27.4.2.6 callbacks:
			enum event { 
				erase_event, imbue_event, copyfmt_event 
			};
			
			typedef void (*event_call_back)(event, ios_base&, int index);
			
			void register_callback(event_call_back fn, int index)
			{ // TODO
			}
			
			static bool sync_with_stdio(bool sync = true)				
			{ // TODO
				if (sync) {
					fflush(stdout);
					fflush(stderr);
				}
				return true;
			}
	
		protected:
			ios_base()
			{
			}
			
		private:
			static int index;
			long* iarray;
			void** parray;
			locale curloc;
	};
	
	// 27.4.4 Template class basic_ios
	template <class charT, class traits>
	class basic_ios : public ios_base
	{
		private:
			basic_streambuf<charT,traits> *sb;
			iostate state;

			/* not defined : 
				basic_ios(const basic_ios&);
				basic_ios& operator=(const basic_ios&);			
			*/
		protected:
			basic_ios()
			{
			}
	
			void init(basic_streambuf<charT, traits> *sb)
			{
				state = 0;
				this->sb = sb;				
			}
		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 traits                    traits_type;

			operator void*() const
			{ 
				if (fail()) 
					return 0;
				return (void *)this;
			}

			bool operator!() const
			{
				return fail();
			}
			
			iostate rdstate() const
			{
				return this->state;
			}
			
			void clear(iostate state = goodbit)
			{
				if (rdbuf() != 0)
					this->state = state;
				else
				 	this->state = state | ios_base::badbit;
				/* doesn't work correctly ... 
				if (rdstate() != 0)
					throw basic_ios::failure("Failure"); */
			}
			
			void setstate(iostate state)			
			{
				clear(rdstate() | state);
			}
	
			bool good() const
			{
				return rdstate() == 0;
			}
			
			bool eof()  const
			{
				return (rdstate() & ios_base::eofbit);
			}
			
			bool fail() const
			{
				return (rdstate() & (ios_base::failbit | ios_base::badbit));
			}
			
			bool bad()  const
			{
				return (rdstate() & ios_base::badbit);
			}
			
			iostate exceptions() const
			{
				return rdstate();
			}
			
			void exceptions(iostate except)
			{ 
				clear(except);
			}
			
			// 27.4.4.1 Constructor / destructor
			explicit basic_ios(basic_streambuf<charT,traits>* sb)
			{
				this->init(sb);
			}
			
			virtual ~basic_ios()
			{
			}
			
			// 27.4.4.2 Members:
			basic_ostream<charT,traits>* tie() const
			{ // TODO
			}
			
			basic_ostream<charT,traits>* tie(basic_ostream<charT,traits>* tiestr)
			{ // TODO
			}
			
			basic_streambuf<charT,traits>* rdbuf() const
			{
				return sb;
			}
			
			basic_streambuf<charT,traits>* rdbuf(basic_streambuf<charT,traits>* sbuf)
			{
				basic_streambuf<charT,traits>* tmp = rdbuf();
				clear();
				sb = sbuf;
				return sb;
			}
			
			basic_ios& copyfmt(const basic_ios& rhs)
			{ // TODO
			}
			
			char_type fill() const
			{ // TODO
			}
			
			char_type fill(char_type ch)
			{ // TODO
			}
			
			locale imbue(const locale& loc)
			{
				const locale tmp = ios_base::getloc();
				ios_base::imbue(loc);
				if (rdbuf() != 0)
					rdbuf()->pubimbue(loc);
				return tmp;
			}
			
			char     narrow(char_type c, char dfault) const
			{
			// return use_facet<ctype<char_type> >(getloc()).narrow(c, dfault);
			}
			
			char_type widen(char c) const
			{
			// return use_facet<ctype<char_type> >(getloc()).widen(c);
				return c;
			}			
	};
	
	// 27.4.5, manipulators: 
	inline ios_base &boolalpha  (ios_base &str)
	{
		str.setf(ios_base::boolalpha);
		return str;
	}

	inline ios_base &noboolalpha(ios_base &str)
	{
		str.unsetf(ios_base::boolalpha);
		return str;
	}
	
	inline ios_base &showbase   (ios_base &str)
	{
		str.setf(ios_base::showbase);
		return str;
	}
	
	inline ios_base &noshowbase (ios_base &str)
	{
		str.unsetf(ios_base::showbase);
		return str;
	}
	
	inline ios_base &showpoint  (ios_base &str)
	{
		str.setf(ios_base::showpoint);
		return str;
	}
	
	inline ios_base &noshowpoint(ios_base &str)
	{
		str.unsetf(ios_base::showpoint);
		return str;
	}
	
	inline ios_base &showpos    (ios_base &str)
	{
		str.setf(ios_base::showpos);
		return str;
	}
	
	inline ios_base &noshowpos  (ios_base &str)
	{
		str.unsetf(ios_base::showpos);
		return str;
	}
	
	inline ios_base &skipws     (ios_base &str)
	{
		str.setf(ios_base::skipws);
		return str;
	}
	
	inline ios_base &noskipws   (ios_base &str)
	{
		str.unsetf(ios_base::skipws);
		return str;	
	}
	
	inline ios_base &uppercase  (ios_base &str)
	{
		str.setf(ios_base::uppercase);
		return str;
	}
	
	inline ios_base &nouppercase(ios_base &str)
	{
		str.unsetf(ios_base::uppercase);
		return str;
	}
	

	// 27.4.5.2 adjustfield:
	inline ios_base &internal   (ios_base &str)
	{
		str.setf(ios_base::internal, ios_base::adjustfield);
		return str;
	}
	
	inline ios_base &left       (ios_base &str)
	{
		str.setf(ios_base::left, ios_base::adjustfield);
		return str;
	}
	
	inline ios_base &right      (ios_base &str)	
	{
		str.setf(ios_base::right, ios_base::adjustfield);
		return str;
	}
	
	// 27.4.5.3 basefield :
	inline ios_base &dec        (ios_base &str)
	{
		curfmt.base = 10;
		str.setf(ios_base::dec, ios_base::basefield);
		return str;
	}
		
	inline ios_base &hex        (ios_base &str)
	{
		curfmt.base = 16;
		str.setf(ios_base::hex, ios_base::basefield);
		return str;
	}
	
	inline ios_base &oct        (ios_base &str)	
	{
		curfmt.base = 8;
		str.setf(ios_base::oct, ios_base::basefield);
		return str;
	}
	
	// 27.4.5.4 floatfield :
	inline ios_base &fixed      (ios_base &str)
	{
		str.setf(ios_base::fixed, ios_base::floatfield);
		return str;
	}

	inline ios_base &scientific (ios_base &str)
	{
		str.setf(ios_base::scientific, ios_base::floatfield);
		return str;
	}	
}

#endif
