#ifndef __BITARRAY_AMV
	#define __BITARRAY_AMV

#include <limits>
#include <iostream>
#include "algorithm.h"
#include "amvdefs.h"

namespace amv	{

const int nBits=std::numeric_limits<unsigned int>::digits;
const unsigned int maxBit=(1<<(nBits-1));
const unsigned int minBit=1;
const unsigned int maxVal=std::numeric_limits<unsigned int>::max();

class bitarray	{
	int m_size;
	int nBlocks;
	unsigned int *pBlocks;
	
	class bit	{
		unsigned int * const pBlock;
		int nBit;

	public:
		bit(unsigned int *pBlocks, int subscript);
		bool operator=(bool value);
		operator bool() const;
	};

public:
	bitarray(int size);
	bitarray(const bitarray &b);
	~bitarray();
	bitarray &operator=(bool val);
	bool operator[](int subscript) const;
	bit operator[](int subscript);
	int bytes() const;
	int size() const;
	void resize(int size);
	int count(bool val);
	int find(bool val);
	friend ostream &operator<<(ostream &os, const bitarray &b);
};

//Funciones miembro de la clase bitarray::bit

inline bitarray::bit::bit(unsigned int *pBlocks, int subscript):
pBlock(pBlocks+subscript/nBits),
nBit(subscript%nBits)
{
}

inline bool bitarray::bit::operator=(bool value)
{
if(value)
	*pBlock|=maxBit>>nBit;
else
	*pBlock&=~(maxBit>>nBit);
return value;
}

inline bitarray::bit::operator bool() const
{
return (*pBlock & (maxBit>>nBit)) ? true : false;
}

//Funciones miembro de la clase bitarray

inline bitarray::bitarray(int size): m_size(size),
nBlocks(m_size%nBits ? m_size/nBits+1 : m_size/nBits),
pBlocks(new unsigned int[nBlocks])
{
unsigned int *pTemp=pBlocks, *pEnd=pBlocks+nBlocks;
while(pTemp!=pEnd)
	{
	*pTemp=0;
	++pTemp;
	}
}

inline bitarray::bitarray(const bitarray &b): m_size(b.m_size),
nBlocks(b.nBlocks),
pBlocks(new unsigned int[nBlocks])
{
copy(b.pBlocks,b.pBlocks+b.nBlocks,pBlocks);
}

inline bitarray::~bitarray()
{
delete [] pBlocks;
}

inline bitarray &bitarray::operator=(bool val)
{
unsigned int *pBegin=pBlocks, *pEnd=pBlocks+nBlocks;

if(val)
	{
	while(pBegin!=pEnd)
		{
		*pBegin=maxVal;
		++pBegin;
		}
	}
else
	{
	while(pBegin!=pEnd)
		{
		*pBegin=0;
		++pBegin;
		}
	}

return *this;
}

inline bool bitarray::operator[](int subscript) const
{
return (*(pBlocks+subscript/nBits) & (maxBit>>(subscript%nBits)));
}

inline bitarray::bit bitarray::operator[](int subscript)
{
return bit(pBlocks,subscript);
}

inline int bitarray::bytes() const
{
return (nBlocks*sizeof(unsigned int));
}

inline int bitarray::size() const
{
return m_size;
}

inline void bitarray::resize(int size)
{
this->~bitarray();
int nBlocks1=size%nBits ? size/nBits+1 : size/nBits;
unsigned int *pBlocks1=new unsigned int[nBlocks1];
copy(pBlocks,pBlocks+nBlocks,pBlocks1);
//***

unsigned int *pTemp=pBlocks, *pEnd=pBlocks+nBlocks;
while(pTemp!=pEnd)
	{
	*pTemp=0;
	++pTemp;
	}
//***
}

inline int bitarray::count(bool val)
{
int n=0;

for(int i=0; i<m_size; ++i)
	if(bit(pBlocks,i)==val)
		++n;

return n;
}

inline int bitarray::find(bool val)
{
int subscript=-1;

for(int i=0; i<m_size; ++i)
	if(bit(pBlocks,i)==val)
		{
		subscript=i;
		break;
		}

return subscript;
}

//Función amiga de la clase bitarray

ostream &operator<<(ostream &os, const bitarray &b)
{
for(int i=0; i<b.m_size; ++i)
	os<<int(b[i]);
return os;
}

}

#endif