/**********************************************************************
bitvec.h - Vector of bits.
 
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
 
This file is part of the Open Babel project.
For more information, see <http://openbabel.sourceforge.net/>
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
 
This program 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 General Public License for more details.
***********************************************************************/

#ifndef OB_BITVEC_H
#define OB_BITVEC_H

#include <openbabel/babelconfig.h>

#ifdef WIN32
#pragma warning (disable : 4786)
#endif

#if HAVE_IOSTREAM
#include <iostream>
#elif HAVE_IOSTREAM_H
#include <iostream.h>
#endif

#include <algorithm>
#include <vector>
#include <string>

#ifndef SETWORD
#define SETWORD 32
#endif

#ifndef STARTWORDS
#define STARTWORDS 10
#endif //STARTBITS

namespace OpenBabel
{

// class introduction in bitvec.cpp
class OBAPI OBBitVec
{
    int _size;
    std::vector<int> _set;
public:
    OBBitVec()
    {
        _set.resize(STARTWORDS);
        _size=_set.size();
        Clear();
    }
    OBBitVec(int bits)
    {
        _set.resize(bits/SETWORD);
        _size=_set.size();
        Clear();
    }
    /// Copy constructor (result has same number of bits)
    OBBitVec(const OBBitVec&);
    void SetBitOn(int);
    void SetBitOff(int);
    void SetRangeOn(int, int);
    void SetRangeOff(int, int);
    void Fold(int);

    //! \return the index of the first bit that is set to true
    int FirstBit(int)
    {
        return (BitIsSet(0) ? 0  : NextBit(0));
    }
    int NextBit(int);
    //! \return the index of the last bit (for iterating)
    int EndBit()    {        return(-1);    }
    /// \return number of 32 bit words. NOT number of bits.
    int GetSize() const    { return(_size);    }
    /// \return the number of bits
    int CountBits();

    /// \deprecated Use IsEmpty() instead.
    bool Empty()   { return(IsEmpty()); }
    bool IsEmpty();
    ///Number of bits increased if necessary but never decreased
    bool Resize(int maxbits);

    bool BitIsSet(int bit)
    {
        return((bit/SETWORD >= GetSize()) ?
               false : _set[bit/SETWORD]>>(bit%SETWORD)&1);
    }
    bool BitIsOn(int bit)
    {
        return((bit/SETWORD >= GetSize()) ?
               false : _set[bit/SETWORD]>>(bit%SETWORD)&1);
    }

    void FromVecInt(std::vector<int>&);
    void FromString(std::string&,int);
    void ToVecInt(std::vector<int>&);
    void Clear(void);
    //! Inverts every bit in the vector
    void Negate()
    {
        for (int i= 0; i != _size; i++)
        {
            _set[i] = ~_set[i];
        }
    }

    ///Assignment operator but number of bits is not reduced 
    OBBitVec &operator= (const OBBitVec &);
    OBBitVec &operator&= (OBBitVec &);
    OBBitVec &operator|= (OBBitVec &);
    OBBitVec &operator|= (const int i)
    {
        SetBitOn(i);
        return(*this);
    }
    OBBitVec &operator^= (OBBitVec &);
    OBBitVec &operator-= (OBBitVec &);
    OBBitVec &operator+= (OBBitVec &bv);
    bool operator[] (int bit)
    {
        return((bit/SETWORD >= GetSize()) ?
               false : _set[bit/SETWORD]>>(bit%SETWORD)&1);
    }

    friend OBBitVec operator| (OBBitVec &, OBBitVec &);
    friend OBBitVec operator& (OBBitVec &,OBBitVec &);
    friend OBBitVec operator^ (OBBitVec &,OBBitVec &);
    friend OBBitVec operator- (OBBitVec &,OBBitVec &);
    friend bool operator== (const OBBitVec &,const OBBitVec &);

    friend std::istream& operator>> ( std::istream&, OBBitVec& );
    friend std::ostream& operator<< ( std::ostream&, const OBBitVec& ) ;
	
    ///Access to data in word size pieces CM
    void GetWords(std::vector<unsigned int>& vec)
      {
	std::vector<int>::iterator itr;
	for(itr=_set.begin();itr!=_set.end();itr++)
	  vec.push_back(*itr);
      }
};

OBAPI extern void ThrowError(char *);
///This function can change the size of second parameter. There is an alternative with different parameters.
OBAPI double Tanimoto(OBBitVec&,OBBitVec&);

}

#endif // OB_BITVEC_H

//! \file bitvec.h
//! \brief Fast and efficient bitstring class
