//  bignumber : headerfile for the free standard C++ library
//              Implements JAVA-like big decimal / Integer Numbers;           
//
//  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_BIGNUMBER
#define __CPP_BIGNUMBER

#include<cstddef>
#include<cstdio>

#include<ios>
#include<vector>
#include<string>
#include<algorithm>
#include<stdexcept>

namespace std {
	class number_format_error : public logic_error
	{
		public:
			number_format_error(const char *what_arg) : logic_error(what_arg)
			{
			}
	};

	class arimethic_error : public runtime_error
	{
		public:
			arimethic_error(const char *what_arg) : runtime_error(what_arg)
			{
			}
	};

	template<class charT, class traits = char_traits<charT> >
	class basic_biginteger
	{
		private:
			vector<unsigned char> c;          // number is stored to base 256 
			int                   signum;     // signum is -1 for negative numbers
			                                  //            1 for positive numbers
											  //            0 for zero (ever!)
			size_t                nbase;      // current used base for io
						
		public:
						 			
			// default constructors
			basic_biginteger()	: nbase(10)
			{
				signum = 0;
			}
			
			template<class T>
			basic_biginteger(basic_biginteger<T> x) {	operator=(x); }
			
			// signed constructors

			basic_biginteger(long  num, size_t base = 10) : nbase(base) { operator=(num); }
			basic_biginteger(int   num, size_t base = 10) : nbase(base) { operator=((long)num); }
			basic_biginteger(short num, size_t base = 10) : nbase(base) { operator=((long)num); }
			basic_biginteger(char  num, size_t base = 10) : nbase(base) { operator=((long)num); }

			// unsigned constructors
			basic_biginteger(unsigned long  num, size_t base = 10) : nbase(base) { operator=(num); }
			basic_biginteger(unsigned int   num, size_t base = 10) : nbase(base) { operator=((unsigned long)num); }
			basic_biginteger(unsigned short num, size_t base = 10) : nbase(base) { operator=((unsigned long)num); }
			basic_biginteger(unsigned char  num, size_t base = 10) : nbase(base) { operator=((unsigned long)num); }

			// char type constructors
			basic_biginteger(basic_string<charT> str, size_t base = 10) : nbase(base) { operator=(str.c_str()); }
			basic_biginteger(charT* val             , size_t base = 10) : nbase(base) { operator=(val); }

			// FUNCTIONS

			void swap(basic_biginteger &x)
			{
				swap(c, x.c);
				swap(signum, x.signum);
			}
			
			template<class X>
			void pow(X exponent) // (this ^ exponent)
			{
				// TODO
			}

			template<class X, class T>
			void modpow(X exponent, T m) // (this ^ exponent) % m
			{
				pow(exponent);
				operator%(m);
			}
			
			int sgn() const
			{
				return signum;
			}

			basic_string<charT> to_string(int base = 10) const
			{
				basic_string<charT> tmp;
				if (sgn() == -1) 
					tmp = "-";
				else
				if (sgn() == 0) {
					tmp = "0";
					return tmp;
				}

				for (unsigned int x = 0 ; x < c.size() ; x++) {
					tmp+= c[x] + '0';
				}
				return tmp;
			}

			// OPERATORS
			
			template<class T>
			basic_biginteger& operator=(basic_biginteger<T> x)
			{
				c = x.c;
				signum = x.signum;
			}

			basic_biginteger& operator=(const charT* v)
			{ // TODO

				bool zero = false;

				signum = 1;
				if (*v == '+')
					v++;
				else
				if (*v == '-') {
					signum = -1;
					v++;
				}
				basic_biginteger tmp(0);

				while (*v != 0) {
					tmp = tmp * nbase + (*v - '0');
					if (*v != '0')
						zero = false;
					v++;
				}
				
				if (zero)
					signum = 0;
				
				return *this;
			}

			basic_biginteger& operator=(long num)
			{
				signum = (num == 0) ? 0 : ((num > 0) ? 1 : 0);

				while (num > 0) {
					c.push_back(num % 256);
					num /= 256;
				}
				return *this;
			}

			basic_biginteger& operator=(unsigned long num)
			{
				signum = (num > 0) ? 1 : 0;

				while (num > 0) {
					c.push_back(num % 256);
					num /= 256;
				}
				return *this;
			}

			// ARIMETHICAL OPERATIONS

			template<class T>
			basic_biginteger& operator+=(basic_biginteger<T>& x)
			{
				if (sgn() == 0) {
					*this = x;
				} else
				if (x.sgn() != 0) {
					int tmp = 0;
					x.c.push_back(0);
					for (unsigned int i = 0 ; i < x.c.size(); i++) {
						if (i >= c.size())
							c.push_back(0);
						tmp /= 256;
						tmp = sgn() * c[i] + x.sgn() * x.c[i] + tmp;
						c[i] = tmp % 256;
					}
					x.c.pop_back();
				}
				return *this;
			}

			template<class T>
			basic_biginteger& operator-=(basic_biginteger<T>& x)
			{ 
				return *this + (-x);
			}

			template<class T>
			basic_biginteger& operator*=(basic_biginteger<T>& x)
			{
				if (sgn() == 0 || x.sgn() == 0) {
					signum = 0;
				} else {
					basic_biginteger<T> tmp = x;
					while (tmp--)
						*this = *this + x;
				}
				return *this;
			}

			template<class T>
			basic_biginteger& operator/=(basic_biginteger<T>& x)
			{ 
				if (sgn() == 0 )  
					return *this;
				if (x.sgn() == 0) 
					throw arimethic_error("divison through 0");

				// TODO

				return *this;
			}

			template<class T>
			basic_biginteger& operator%=(basic_biginteger<T>& x)
			{ 
				if (x.sgn() <= 0) 
					throw arimethic_error("modulus operator should be >0");
				if (sgn() == 0)
					return *this;
					
				// TODO

				return *this;
			}

			template<class X>
			basic_biginteger& operator<<=(X val)
			{
				while (val > 0)
					*this *= 2;
				return *this;
			}
			
			template<class X>
			basic_biginteger& operator>>=(X val)
			{
				while (val > 0)
					*this /= 2;
				return *this;
			}

			// UNARY ARIMETHICAL OPERATORS
			basic_biginteger& operator -()
			{
				signum *= -1;
				return *this;				
			}
			
			basic_biginteger& operator +()
			{
				return *this;
			}
	
			basic_biginteger& operator --()
			{
				return *this - basic_biginteger<charT>(1);
			}
			
			basic_biginteger& operator --(int)
			{
				basic_biginteger tmp = *this;
				*this--;
				return tmp;
			}

			basic_biginteger& operator ++()
			{
				return *this - basic_biginteger<charT>(1);
			}

			basic_biginteger& operator ++(int)
			{
				basic_biginteger tmp = *this;
				*this++;
				return tmp;
			}

			// LOGICAL OPERATIONS
			
			template<class T>
			basic_biginteger& operator&=(basic_biginteger<T>& x)
			{
				if (c.size < x.c.size)
					transform(c.begin(), c.end(), c.x.begin(), c.begin(), binary_and<T>());
				else
					transform(c.x.begin(), c.x.end(), c.begin(), c.begin(), binary_and<T>());
				return *this;
			}
			
			template<class T>
			basic_biginteger& operator|=(basic_biginteger<T>& x)
			{
				if (c.size < x.c.size)
					transform(c.begin(), c.end(), c.x.begin(), c.begin(), binary_or<T>());
				else
					transform(c.x.begin(), c.x.end(), c.begin(), c.begin(), binary_or<T>());
				return *this;
			}

			template<class T>
			basic_biginteger& operator^=(basic_biginteger<T>& x)
			{
				if (c.size < x.c.size)
					transform(c.begin(), c.end(), c.x.begin(), c.begin(), binary_xor<T>());
				else
					transform(c.x.begin(), c.x.end(), c.begin(), c.begin(), binary_xor<T>());
				return *this;
			}

			template<class T>
			basic_biginteger& operator~()
			{
				transform(c.begin(), c.end(), c.begin(), binary_not<T>());
				return *this;
			}

	};

	typedef basic_biginteger<char>    biginteger;
	typedef basic_biginteger<wchar_t> wbiginteger;

	template<class T, class charT, class traits>
	basic_biginteger<charT,traits>& operator+(basic_biginteger<charT,traits>& x,T val)
	{
		return basic_biginteger<charT, traits>(val) += x;
	}



	template<class charT>
	basic_biginteger<charT> sgn(basic_biginteger<charT>& x)
	{
		return x.sgn();	
	}

	template<class charT>
	basic_biginteger<charT> abs(basic_biginteger<charT>& x)
	{
		if (x.sgn() < 0)
			return -x;
		return x;
	}
	
	template<class charT>
	bool operator==(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() == y.to_string();
	}
	
	template<class charT>
	bool operator!=(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() != y.to_string();
	}

	template<class charT>
	bool operator<(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() < y.to_string();
	}

	template<class charT>
	bool operator>(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() > y.to_string();
	}

	template<class charT>
	bool operator>=(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() >= y.to_string();
	}

	template<class charT>
	bool operator<=(basic_biginteger<charT>& x, basic_biginteger<charT>& y)
	{
		return x.to_string() <= y.to_string();
	}

	template<class charT, class charT2>
	void swap(basic_biginteger<charT>& x, basic_biginteger<charT2>& y)
	{
		x.swap(y);
	}
	
	template<class T, class charT, class traits> 
	basic_istream<charT, traits> &operator>>(basic_istream<charT, traits>& is, basic_biginteger<T>& x)
	{  // NOT 100%
		basic_string<T> tmp;
		is >> tmp;
		x = tmp;
		return is;
	}

	template<class T, class charT, class traits>
	basic_ostream<charT, traits> &operator<<(basic_ostream<charT, traits>& os, const basic_biginteger<T>& x)
	{
		os << (x.to_string(curfmt.base)).c_str();
		return os;
	}
}

#endif
