//  bitset : 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_BITSET
#define __CPP_BITSET

#include <cstddef>
#include <new>

#include <stdexcept>  // for invalid_argument, out_of_range, overflow_error
#include <ios>        // for istream, ostream
#include <string>

namespace std {
	
	// 23.3.5 Template class bitset
	template <size_t N> 
	class bitset
	{
		private:
			unsigned char bitfield[(N / 8) + 1];
		public:
			// bit reference
			class reference {
					friend class bitset;
					reference()
					{
					}
				public:
					~reference()
					{
					}
					reference& operator=(bool x)
					{
					}
					reference& operator=(const reference &ref)
					{
					}
					bool operator~() const
					{
					}
					operator bool() const
					{
					}
					reference& flip()
					{
					}
			};
			
			// 23.3.5.1 constructors:
			bitset()
			{
				reset();			
			}

			bitset(unsigned long val)
			{
				unsigned int num = N;
				reset();
				while (val) {
					if (val & 1)
						set (num--, true);
					val /= 2;
				}
			}
			/*
			template<class charT, class traits, class Allocator>
			explicit bitset(const basic_string<charT, traits, Allocator> &str, 
			                typename basic_string<charT,traits,Allocator>::size_type pos = 0, 
							typename basic_string<charT,traits,Allocator>::size_type n   = basic_string<charT, traits, Allocator>::npos)
			{
				reset();			
			}*/
			
			/// NON-STANDARD OPERATION :
			bitset<N>& operator=(const bitset<N>& rhs)				
			{
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] = rhs.bitfield[x];
				return *this;
			}

			// 23.3.5.2 bitset operations
			bitset<N>& operator&=(const bitset<N>& rhs)				
			{
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] &= rhs.bitfield[x];
				return *this;
			}

			bitset<N>& operator|=(const bitset<N>& rhs)
			{
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] |= rhs.bitfield[x];	
				return *this;
			}
			
			bitset<N>& operator^=(const bitset<N>& rhs)
			{
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] ^= rhs.bitfield[x];
				return *this;
			}
			
			bitset<N>& operator<<=(size_t pos)
			{ // TODO
				return *this;
			}
			
			bitset<N>& operator>>=(size_t pos)
			{ // TODO
				return *this;
			}
			
			bitset<N>& set()
			{
				memset(bitfield, 0xFF, sizeof(bitfield));
				return *this;
			}
			
			bitset<N>& set(size_t pos, int val = true)
			{
				if (pos / 8 >= N)
					throw out_of_range("index out of range");			
				bitfield[pos / 8] = val ? (1 << (pos % 8)) : 0;
				return *this;
			}
			
			bitset<N>& reset()
			{
				memset(bitfield, 0, sizeof(bitfield));
				return *this;
			}
			
			bitset<N>& reset(size_t pos)
			{
				if (pos / 8>= N)
					throw out_of_range("index out of range");			
				bitfield[pos / 8] &= ~(1 << (pos % 8));
				return *this;
			}
			
			bitset<N>  operator~() const
			{
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] = ~bitfield[x];
				return *this;
			}
			
			bitset<N>& flip()
			{ // TODO : TEST
				for (int x=0;x<sizeof(bitfield);x++)
					bitfield[x] = ~bitfield[x];			
				return *this;
			}
			
			bitset<N>& flip(size_t pos)
			{
				if (pos /8 >= N)
					throw out_of_range("index out of range");
				bitfield[pos / 8] ^= (1 << (pos % 8));
				return *this;
			}
		
			// element access:
			reference operator[](size_t pos)
			{ // TODO
			}
			
			unsigned long  to_ulong() const
			{ // TODO
			}
			
/*			template <class charT, class traits, class Allocator>
			basic_string<charT, traits, Allocator>*/
			string to_string()  const
			{
				string str = "";
				for (int x=0;x<N;x++) {
					str = ((bitfield[x/8] & (1 << (x % 8))) ? '1' : '0') + str;
				}
				return str;
			}
			
			size_t count() const
			{ // TODO
			}
			
			size_t size()  const
			{ // TODO
			}
			
			bool operator==(const bitset<N>& rhs) const
			{
				for (int x=0;x<sizeof(bitfield);x++)
					if (bitfield[x] != rhs.bitfield[x])
						return false;
				return true;
			}
			
			bool operator!=(const bitset<N>& rhs) const
			{
				return !operator==(rhs);
			}
			
			bool test(size_t pos) const
			{ // TODO
			}
		
			bool any() const
			{ // TODO
			} 
			
			bool none() const
			{ // TODO
			}
			
			bitset<N> operator<<(size_t pos) const
			{ // TODO
			}
			
			bitset<N> operator>>(size_t pos) const
			{ // TODO
			}
	};
	
	// 23.3.5.3 bitset operations:
	template <size_t N> 
	bitset<N> operator &(const bitset<N> &x, const bitset<N> &y)
	{
		return bitset<N>(x) &= y;
	}

	template <size_t N>
	bitset<N> operator|(const bitset<N> &x, const bitset<N> &y)	
	{
		return bitset<N>(x) &= y;	
	}
    
	template <size_t N> 
	bitset<N> operator^(const bitset<N> &x, const bitset<N> &y)
	{
		return bitset<N>(x) ^= y;
	}
	
	template <class charT, class traits, size_t N>
	basic_istream<charT, traits> &operator>>(basic_istream<charT, traits> &is, bitset<N> &x)
	{
		string tmp;
		is >> tmp;
		x = bitset<N>(tmp);
		return os;
	}

	template <class charT, class traits, size_t N>
	basic_ostream<charT, traits> &operator<<(basic_ostream<charT, traits> &os, const bitset<N> &x)
	{
		string s = x.to_string();
		os << s;
		return os;
	}
}
#endif
