/*	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
*/
#pragma once
#ifdef ARDUINO_ARCH_AVR
#pragma GCC visibility push(default)
#include "streambuf"
#include <stdio.h>
namespace std
{
#ifdef ARDUINO_ARCH_AVR
	typedef signed long int streamoff;
#endif
	template <class stateT>
	class fpos;


	// ios_base 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;
	}

	inline ios_base &unitbuf(ios_base &str)
	{
		str.setf(ios_base::unitbuf);
		return str;
	}
	inline ios_base &nounitbuf(ios_base &str)
	{
		str.unsetf(ios_base::unitbuf);
		return str;
	}
	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;
	}

	inline ios_base &dec(ios_base &str)
	{
		str.setf(ios_base::dec, ios_base::basefield);
		return str;
	}
	inline ios_base &hex(ios_base &str)
	{
		str.setf(ios_base::hex, ios_base::basefield);
		return str;
	}
	inline ios_base &oct(ios_base &str)
	{
		str.setf(ios_base::oct, ios_base::basefield);
		return str;
	}

	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;
	}

	// basic_ios class definition

	template <class charT, class traits>
	class _UCXXEXPORT basic_ios
		: public ios_base
	{
	public:
		// Types:
		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;

		_UCXXEXPORT operator void *() const
		{
			if (fail())
			{
				return 0;
			}
			return (void *)(1); // Must return a non-NULL pointer (though it can be *any* pointer)
		}

		_UCXXEXPORT bool operator!() const
		{
			return fail();
		}
		_UCXXEXPORT iostate rdstate() const
		{
			return mstate;
		}
		_UCXXEXPORT void clear(iostate state = goodbit)
		{
			if (rdbuf() != 0)
			{
				mstate = state;
			}
			else
			{
				mstate = state | ios_base::badbit;
			}
		}
		_UCXXEXPORT void setstate(iostate state)
		{
			clear(rdstate() | state);
#ifdef __UCLIBCXX_EXCEPTION_SUPPORT__
			if (rdstate() & throw_mask)
			{
				throw failure();
			}
#endif
		}

		_UCXXEXPORT bool good() const
		{
			return (rdstate() == 0);
		}
		_UCXXEXPORT bool eof() const
		{
			if (rdstate() & eofbit)
			{
				return true;
			}
			return false;
		}
		_UCXXEXPORT bool fail() const
		{
			if (mstate & (failbit | badbit))
			{
				return true;
			}
			return false;
		}

		_UCXXEXPORT bool bad() const
		{
			if (mstate & badbit)
			{
				return true;
			}
			return false;
		}

		_UCXXEXPORT iostate exceptions() const
		{
			return throw_mask;
		}
		_UCXXEXPORT void exceptions(iostate except)
		{
			throw_mask = except;
		}

		explicit _UCXXEXPORT basic_ios(basic_streambuf<charT, traits> *sb)
			: fill_char(' '), mtied(0), mstreambuf(0), throw_mask(0)
		{
			init(sb);
		}

		basic_ios() : mtied(0), mstreambuf(0) {}

		virtual _UCXXEXPORT ~basic_ios()
		{
		}

		_UCXXEXPORT basic_ostream<charT, traits> *tie() const
		{
			return mtied;
		}
		_UCXXEXPORT basic_ostream<charT, traits> *tie(basic_ostream<charT, traits> *tiestr)
		{
			basic_ostream<charT, traits> *retval = mtied;
			mtied = tiestr;
			return retval;
		}
		_UCXXEXPORT basic_streambuf<charT, traits> *rdbuf() const
		{
			return mstreambuf;
		}
		_UCXXEXPORT basic_streambuf<charT, traits> *rdbuf(basic_streambuf<charT, traits> *sb)
		{
			basic_streambuf<charT, traits> *retval = mstreambuf;
			mstreambuf = sb;
			return retval;
		}
		_UCXXEXPORT basic_ios &copyfmt(const basic_ios &rhs);
		_UCXXEXPORT char_type fill() const
		{
			return fill_char;
		}
		_UCXXEXPORT char_type fill(char_type ch)
		{
			char_type temp = fill_char;
			fill_char = ch;
			return temp;
		}

		_UCXXEXPORT locale imbue(const locale &loc)
		{
			return ios_base::imbue(loc);
		}
		_UCXXEXPORT char narrow(char_type c, char dfault) const;
		_UCXXEXPORT char_type widen(char c) const;

	protected:
		char_type fill_char;
		basic_ostream<charT, traits> *mtied;
		basic_streambuf<charT, traits> *mstreambuf;
		iostate throw_mask;
		_UCXXEXPORT basic_ios(const basic_ios<charT, traits> &) {}
		_UCXXEXPORT basic_ios<charT, traits> &operator=(const basic_ios<charT, traits> &) { return *this; }
		_UCXXEXPORT void init(basic_streambuf<charT, traits> *sb)
		{
			ios_base::mformat = skipws | dec;
			mstreambuf = sb;
			mstate = goodbit;
			throw_mask = goodbit;
		}
	};

#ifdef __UCLIBCXX_EXPAND_IOS_CHAR__
#ifndef __UCLIBCXX_COMPILE_IOS__

	template <>
	_UCXXEXPORT void basic_ios<char, char_traits<char>>::clear(iostate state);
	template <>
	_UCXXEXPORT void basic_ios<char, char_traits<char>>::setstate(iostate state);

#endif
#endif

	template <class charT, class traits>
	inline char basic_ios<charT, traits>::narrow(char_type c, char dfault) const
	{
		return dfault;
	}

	template <>
	inline char basic_ios<char, char_traits<char>>::narrow(char_type c, char) const
	{
		return c;
	}

#if defined(__UCLIBCXX_HAS_WCHAR__) && defined(ARDUINO_ARCH_SAM)

	template <>
	inline char basic_ios<wchar_t, char_traits<wchar_t>>::narrow(char_type c, char dfault) const
	{
		char retval = wctob(c);
		if (retval == EOF)
		{
			retval = dfault;
		}
		return retval;
	}

#endif //__UCLIBCXX_HAS_WCHAR__

	template <class charT, class traits>
	inline typename basic_ios<charT, traits>::char_type
	basic_ios<charT, traits>::widen(char c) const
	{
		return c;
	}

	template <>
	inline basic_ios<char, char_traits<char>>::char_type
	basic_ios<char, char_traits<char>>::widen(char c) const
	{
		return c;
	}

#if defined(__UCLIBCXX_HAS_WCHAR__) && defined(ARDUINO_ARCH_SAM)

	template <>
	inline basic_ios<wchar_t, char_traits<wchar_t>>::char_type
	basic_ios<wchar_t, char_traits<wchar_t>>::widen(char c) const
	{
		return btowc(c);
	}

#endif //__UCLIBCXX_HAS_WCHAR__
#ifdef ARDUINO_ARCH_AVR
	template <class stateT>
	class _UCXXEXPORT fpos
	{
	public:
		_UCXXEXPORT fpos(stateT s)
		{
			st = s;
		}
		_UCXXEXPORT stateT state() const
		{
			return st;
		}
		_UCXXEXPORT void state(stateT s)
		{
			st = s;
		}
		_UCXXEXPORT bool operator==(const fpos &rhs)
		{
			return st == rhs.st;
		}
		_UCXXEXPORT bool operator!=(const fpos &rhs)
		{
			return st != rhs.st;
		}
		_UCXXEXPORT fpos &operator+(const streamoff &o)
		{
			st += o;
			return *this;
		}
		_UCXXEXPORT fpos &operator-(const streamoff &o)
		{
			st -= o;
			return *this;
		}
		_UCXXEXPORT streamoff operator-(const fpos &rhs)
		{
			return st - rhs.st;
		}

	private:
		stateT st;
	};
#endif
}

#pragma GCC visibility pop
#else
#include "Cpp_Standard_Library.h"
#include _CSL_Official(ios)
#endif