/*	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 STD_HEADER_OSTREAM
#define STD_HEADER_OSTREAM 1

#include <iosfwd>
#include <streambuf>
#include <cstdio>
#include <ostream_helpers>

namespace std {
	template <class charT, class traits > class basic_ostream;
	typedef basic_ostream<char> ostream;
	typedef basic_ostream<wchar_t> wostream;

	template <class charT, class traits> basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
	template <class charT, class traits> basic_ostream<charT,traits>& ends(basic_ostream<charT,traits>& os);
	template <class charT, class traits> basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os);

	template <class charT, class traits > class basic_ostream : virtual public basic_ios<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 traits traits_type;


		basic_ostream(basic_streambuf<charT,traits>* sb): sbuffer(sb){
			basic_ios<charT,traits>::init(sb);
		}
		virtual ~basic_ostream();

		class sentry;

		basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&)){
			return pf(*this);
		}
		basic_ostream<charT,traits>& operator<<(basic_ios<charT,traits>& (*pf)(basic_ios<charT,traits>&)){
			pf(*this);
			return *this;
		}
		basic_ostream<charT,traits>& operator<<(ios_base& (*pf)(ios_base&)){
			pf(*this);
			return *this;
		}
		basic_ostream<charT,traits>& operator<<(bool n);
		basic_ostream<charT,traits>& operator<<(short n);
		basic_ostream<charT,traits>& operator<<(unsigned short n);
		basic_ostream<charT,traits>& operator<<(int n);
		basic_ostream<charT,traits>& operator<<(unsigned int n);
		basic_ostream<charT,traits>& operator<<(long n);
		basic_ostream<charT,traits>& operator<<(unsigned long n);
		basic_ostream<charT,traits>& operator<<(float f);
		basic_ostream<charT,traits>& operator<<(double f);
		basic_ostream<charT,traits>& operator<<(long double f);
		basic_ostream<charT,traits>& operator<<(void* p);
		basic_ostream<charT,traits>& operator<<(basic_streambuf<char_type,traits>* sb);
		basic_ostream<charT,traits>& put(char_type c){
			sbuffer->sputc(c);
			flush();
			return *this;
		}
		basic_ostream<charT,traits>& write(const char_type* s, streamsize n){
			sbuffer->sputn(s, n);
			return *this;
		}
		basic_ostream<charT,traits>& flush(){
			if(sbuffer->pubsync() == -1){
				basic_ios<charT,traits>::setstate(ios_base::badbit);
			}
			return *this;
		}
		pos_type tellp(){
			if(basic_ios<charT,traits>::fail() != false){
				return pos_type(-1);
			}
			return basic_ios<charT,traits>::rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
		}
		basic_ostream<charT,traits>& seekp(pos_type pos){
			if( basic_ios<charT,traits>::fail() != true ){
				basic_ios<charT,traits>::rdbuf()->pubseekpos(pos);
			}
			return *this;
		}
		basic_ostream<charT,traits>& seekp(off_type off, ios_base::seekdir dir){
			if( basic_ios<charT,traits>::fail() != true){
				basic_ios<charT,traits>::rdbuf()->pubseekoff(off, dir);
			}
			return *this;
		}

	protected:
		basic_streambuf<char_type,traits>* sbuffer;
		basic_ostream(const basic_ostream<charT,traits> &){ }
		basic_ostream<charT,traits> & operator=(const basic_ostream<charT,traits> &){ return *this; }
	};

	//Implementations of template functions.  To allow for partial specialization

	template <class charT, class traits> basic_ostream<charT,traits>::~basic_ostream(){
		flush();
	}
	
	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(bool n){
		sentry s(*this);
		if( basic_ios<charT,traits>::flags() & ios_base::boolalpha){
			if(n){
				write("true", 4);
			}else{
				write("false", 5);
			}
		}else{
			if(n){
				write("1", 1);
			}else{
				write("0", 1);
			}
		}
		if(basic_ios<charT,traits>::flags() & ios_base::unitbuf){
			flush();
		}
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& 
		basic_ostream<charT, traits>::operator<<(unsigned short n){
		sentry s(*this);
		__ostream_printout<traits, charT, unsigned long int>::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(short n){
		sentry s(*this);
		__ostream_printout<traits, charT, long int>::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(int n){
		sentry s(*this);
		__ostream_printout<traits, charT, long int>::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(unsigned int n){
		sentry s(*this);
		__ostream_printout<traits, charT, unsigned long int>::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(long n){
		sentry s(*this);
		__ostream_printout<traits, charT, long >::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& 
		basic_ostream<charT, traits>::operator<<(unsigned long n)
	{
		sentry s(*this);
		__ostream_printout<traits, charT, unsigned long >::printout(*this, n);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(float f){
		sentry s(*this);
		__ostream_printout<traits, charT, double >::printout(*this, f);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(double f){
		sentry s(*this);
		__ostream_printout<traits, charT, double >::printout(*this, f);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(long double f){
		sentry s(*this);
		__ostream_printout<traits, charT, long double >::printout(*this, f);
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& basic_ostream<charT, traits>::operator<<(void* p){
		sentry s(*this);
		char buffer[20];
		write(buffer, snprintf(buffer, 20, "%p", p) );
		if(basic_ios<charT,traits>::flags() & ios_base::unitbuf){
			flush();
		}
		return *this;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& 
		basic_ostream<charT, traits>::operator<<(basic_streambuf<charT,traits>* sb)
	{
		sentry s(*this);
		if(sb == 0){
			basic_ios<charT,traits>::setstate(ios_base::badbit);
			return *this;
		}

		typename traits::int_type c;

		while((c = sb->sgetc()) != traits::eof() ){
			put(c);
		}

		if(basic_ios<charT,traits>::flags() & ios_base::unitbuf){
			flush();
		}
		return *this;
	}

	/*Template Specializations*/

#ifdef __UCLIBCXX_EXPAND_OSTREAM_CHAR__
#ifndef __UCLIBCXX_COMPILE_OSTREAM__

	template <> basic_ostream<char, char_traits<char> >::~basic_ostream();

	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(bool n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(short int n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::
		operator<<(unsigned short int n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(int n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(unsigned int n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(long n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(unsigned long n);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(float f);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(double f);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(long double f);
	template <> basic_ostream<char,char_traits<char> > & basic_ostream<char, char_traits<char> >::operator<<(void* p);
	template <> basic_ostream<char,char_traits<char> > & 
		basic_ostream<char, char_traits<char> >::operator<<(basic_streambuf<char, char_traits<char> >* sb);
#endif
#endif

	template <class charT,class traits = char_traits<charT> > class basic_ostream<charT,traits>::sentry {
		bool ok;
	public:
		explicit sentry(basic_ostream<charT,traits>& os): ok(true){
			if(os.good() !=0){		//Prepare for output
			}

			//Flush any tied buffer
			if(os.tie() !=0 ){
				os.tie()->flush();
			}
		}
		~sentry() { }
		operator bool() {
			return ok;
		}
	};


	//Non - class functions


	template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, charT c){
		typename basic_ostream<charT,traits>::sentry s(out);
		out.put(c);
		return out;
	}
	
	template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, char c){
		typename basic_ostream<charT,traits>::sentry s(out);
		out.put(c);
		return out;
	}
    
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, char c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.put(c);
		return out;
	}
    
    // signed and unsigned
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.put(c);
		return out;
	}
	
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.put(c);
		return out;
	}
	
	template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const charT* c){
		typename basic_ostream<charT,traits>::sentry s(out);
		out.write(c, traits::length(c) );
		return out;
	}
	
	template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const char* c){
		typename basic_ostream<charT,traits>::sentry s(out);
		out.write(c, traits::length(c) );
		return out;
	}

    // partial specializations
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.write(c, traits::length(c));
		return out;
	}

    
    //  signed and unsigned
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const signed char* c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.write(c, traits::length(c));
		return out;
	}
	
	template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const unsigned char* c){
		typename basic_ostream<char,traits>::sentry s(out);
		out.write(c, traits::length(c));
		return out;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os){
		typename basic_ostream<char,traits>::sentry s(os);
		os.put('\n');
		os.flush();
		return os;
	}

	template <class charT, class traits> basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os){
		typename basic_ostream<char,traits>::sentry s(os);
		os.flush();
		return os;
	}


#ifdef __UCLIBCXX_EXPAND_OSTREAM_CHAR__
#ifndef __UCLIBCXX_COMPILE_OSTREAM__
	template <> basic_ostream<char,char_traits<char> >& endl(basic_ostream<char,char_traits<char> >& os);
	template <> basic_ostream<char,char_traits<char> >& flush(basic_ostream<char,char_traits<char> >& os);
	template <> basic_ostream<char,char_traits<char> >& 
		operator<<(basic_ostream<char,char_traits<char> >& out, const char* c);

#endif
#endif


#ifndef __STRICT_ANSI__

//Support for output of long long data types

template<class Ch, class Tr> basic_ostream<Ch, Tr>& 
	operator<<(basic_ostream<Ch, Tr>& os, signed long long int i)
{
	typename basic_ostream<Ch, Tr>::sentry s(os);
	__ostream_printout<Tr, Ch, signed long long int>::printout(os, i);
	return os;
}


template<class Ch, class Tr> basic_ostream<Ch, Tr>& 
	operator<<(basic_ostream<Ch, Tr>& os, unsigned long long int i)
{
	typename basic_ostream<Ch, Tr>::sentry s(os);
	__ostream_printout<Tr, Ch, unsigned long long int>::printout(os, i);
	return os;
}


#endif	//__STRICT_ANSI__




}


#endif

