/* 
 */

#ifndef _BINGO_PG_EXT_BITSET_H__
#define	_BINGO_PG_EXT_BITSET_H__

#include "base_cpp/array.h"
#include "base_cpp/exception.h"

class BingoPgExternalBitset {
public:
   BingoPgExternalBitset();
   BingoPgExternalBitset(int nbits);

   inline int begin() const {return nextSetBit(0);}
   inline int end() const {return -1;}
   inline int next(int idx) const {return nextSetBit(idx + 1);}
   
   virtual ~BingoPgExternalBitset(){}

   void* serialize(int& size);
   void deserialize(void* data, int data_len, bool ext);

   //sets the bit at the specified index to the complement of its current value
   void flip(int bitIndex);
   //sets each bit from the specified fromIndex to the specified toIndex (exclusive)
   //to the complement of its current value
   void flip(int fromIndex, int toIndex);
   //sets all bits to the complement values
   void flip();

   //sets all bits to true
   void set();
   //sets the bit at the specified index to true
   void set(int bitIndex);
   //sets the bit at the specified index to the specified value.
   void set(int bitIndex, bool value);
   //sets the bits from the specified fromIndex to the specified toIndex(exclusive)
   void set(int fromIndex, int toIndex);
   //sets the bit specified by the index to false
   void reset(int bitIndex);
   //sets all of the bits in this BitSet to false
   void clear();
   //returns the value of the bit with the specified index
   bool get(int bitIndex) const;
   //returns the index of the first bit that is set to true
   //that occurs on or after the specified starting index. If no such
   //bit exists then -1 is returned
   int nextSetBit(int fromIndex) const;
   //returns true if BitSet contains no bits that are set true
   bool isEmpty() const {return (*_lastWordPtr) == 0; };
   //Returns true if the specified BitSet has any bits set to true
   //that are also set to true in this BitSet
   bool intersects(const BingoPgExternalBitset& set) const;
   //Performs a logical AND of this target BitSet with the argument BitSet
   void andWith(const BingoPgExternalBitset& set);
   //Performs a logical OR of this target BitSet with the argument BitSet
   void orWith(const BingoPgExternalBitset& set);
   //Performs a logical XOR of this target BitSet with the argument BitSet
   void xorWith(const BingoPgExternalBitset& set);
   //Clears all of the bits in this BitSet whose corresponding
   // bit is set in the specified BitSet.
   void andNotWith(const BingoPgExternalBitset& set);
   //Returns the number of bits of space actually in use by this
   //BitSet to represent bit values
   int size() const {return _bitsNumber; };
   //Compares this BitSet against the specified BitSet.
   bool equals(const BingoPgExternalBitset& set) const;
   //Cloning this BitSet produces a new BitSet
   void copy(const BingoPgExternalBitset& set);
   //copy part of BitSet
   void copySubset(const BingoPgExternalBitset& set);
   //resizes this BitSet
//   void resize(int size);
   //checks if this BitSet is subset of argument BitSet
   bool isSubsetOf(const BingoPgExternalBitset& set) const;
   //checks if this BitSet is proper subset of argument BitSet
   bool isProperSubsetOf(const BingoPgExternalBitset& set) const;

   //fills with false all bits in this BitSet
   void zeroFill();

   void bsOrBs(const BingoPgExternalBitset& set1,const BingoPgExternalBitset& set2);
   //Clears all of the bits in first argument BitSet whose corresponding
   // bits is set in the specified second argument BitSet. Result -> this
   void bsAndNotBs(const BingoPgExternalBitset& set1,const BingoPgExternalBitset& set2);
   //Performs a logical AND of two argument BitSets. result saves to this Bitset
   void bsAndBs(const BingoPgExternalBitset& set1,const BingoPgExternalBitset& set2);
   int bitsNumber() const;
   bool hasBits() const;

   qword shiftOne(int shiftNumber);

private:
   BingoPgExternalBitset(const BingoPgExternalBitset&); //no implicit copy

   //bitsets are packed into arrays of "words."  Currently a word is
   //a long long, which consists of 64 bits, requiring 6 address bits.
   //The choice of word size is determined purely by performance concerns.

   enum {
      ADDRESS_BITS_PER_WORD = 6,
      BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD,
      MAX_SHIFT_NUMBER = 63
   };
   static const qword WORD_MASK = 0xFFFFFFFFFFFFFFFFULL;

   //the number of words in the logical size of this BitSet.
   qword* _lastWordPtr;
   qword _lastWord;
   //bits number in bitset
   int _bitsNumber;
   //words size
   int _length;
   //given a bit index, return word index containing it.
   static int _wordIndex(int bitIndex) { return bitIndex >> ADDRESS_BITS_PER_WORD; }
   //set the field wordsInUse with the logical size in words of the bit
   //set.  WARNING:This method assumes that the number of words actually
   //in use is less than or equal to the current value of wordsInUse!
   void _recalculateWordsInUse();
   //creates a new bit set. All bits are initially false.
   void _initWords(int nbits);
   // ensures that the BitSet can accommodate a given wordIndex
   void _expandTo(int wordIndex);

   int _bitCount(qword b) const;

   int _leastSignificantBitPosition(qword n) const;

   inline int _wordsInUse() {return (int)*_lastWordPtr;};

   qword* _words;
   
   indigo::Array<qword> _internalWords;
   indigo::Array<qword> _serializeWords;
public:
   class Iterator {
   public:
      Iterator(BingoPgExternalBitset&);

      ~Iterator() {
      }

      int begin();
      int next();

      inline int end() {
         return -1;
      }

   private:

      void _fillIndexes(byte buf, indigo::Array<int>&indexes);
      int _wordsInUse;
      qword* _words;

      int _fromWordIdx;
      int _fromByteIdx;
      int _fromBitIdx;
      qword* _fromWord;
      indigo::Array<int>* _fromIndexes;

      int _shiftByte;
      int _shiftWord;

   private:
      Iterator(const Iterator&); //no implicit copy
      };
};


#endif	/* EXT_BITSET_H */

