/***************************************************************************
 *   Copyright (C) 2000-2010 by Noel Novelli                               *
 *   novelli@lif.univ-mrs.fr                                               *
 *                                                                         *
 *   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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#ifndef __ATTRIBUTE_H__
#define __ATTRIBUTE_H__

#include <iostream>
#include <cstdlib>


class Attribute
{

private:
	static const unsigned int MAX_ATTRIBUTE = 32;

public:
	////////////////////////////////////
	// STATIC Methods

    static void InitMaxNbAttribute( unsigned int uMaxNbAttribute )
    {
        if ( uMaxNbAttribute > GetMaxAttribute( ) )
        {
			std::cerr << "Attribute::InitNbAlloc uMaxNbAttribute > MAX_ATTRIBUTE ["
                 << uMaxNbAttribute << " < " << GetMaxAttribute( ) << ']' << std::endl;
            exit( -2 );
        }
    }

    static unsigned int GetMaxAttribute( )
    {
        return MAX_ATTRIBUTE;
    }

public:
        //////////////////////////////////////////////////////
        //
        //          PUBLIC Properties
        //

	unsigned int m_V;


        //////////////////////////////////////////////////////
        //
        //          Constructors & Destructor
        //

	Attribute( ) : m_V( 0 )
    { }

    Attribute( unsigned int V ) : m_V( 1 << V )
    { }

	Attribute( const Attribute &attr ) : m_V( attr.m_V )
	{ }

    ~Attribute( )
    { }

        //////////////////////////////////////////////////////
        //
        //          Methods
        //

    void clear( )
    {
        m_V = 0;
    }

    bool empty( ) const
    {
        return m_V == 0;
    }

    bool contain(unsigned int x) const
    {
	    return (m_V & (1 << x)) != 0;
    }

    void erase(unsigned int x)
    {
        m_V &= ~(1 << x);
    }

    void insert( unsigned int i )
    {
        m_V |= (1 << i);
    }

    unsigned int size() const
    {
	    unsigned int s = 0;

        for ( unsigned int j = 0; j < GetMaxAttribute( ) ; ++j )
            if ( contain( j ) )
				++s;

        return s;
    }

    bool operator ==(const Attribute &bs) const
    {
	    return m_V == bs.m_V;
    }

    bool operator !=(const Attribute &bs) const
    {
	    return m_V != bs.m_V;
    }

	Attribute &operator &=(const Attribute &bs)
    {
	    m_V &= bs.m_V;

    	return *this;
    }

    Attribute operator &(const Attribute &bs) const
    {
        Attribute tmp(*this);
	    tmp &= bs;
	    return tmp;
    }

    Attribute &operator |=(const Attribute &bs)
    {
	    m_V |= bs.m_V;

    	return *this;
    }

    Attribute operator |(const Attribute &bs) const
    {
        Attribute tmp(*this);
	    tmp |= bs;
	    return tmp;
    }

    bool operator <(const Attribute &bs) const
    {
        unsigned int s1 = size( ), s2 = bs.size( );

        if ( s1 < s2 )
            return true;
        if ( s2 < s1 )
            return false;
	    return m_V < bs.m_V;
    }

    bool operator >(const Attribute &bs) const
    {
        unsigned int s1 = size( ), s2 = bs.size( );

        if ( s1 > s2 )
            return true;
        if ( s2 > s1 )
            return false;
	    return m_V > bs.m_V;
    }

    Attribute &operator -=(const Attribute &bs)
    {
	    m_V &= ~bs.m_V;

	    return *this;
    }

    Attribute operator -(const Attribute &bs) const
    {
        Attribute tmp(*this);
	    tmp -= bs;
	    return tmp;
    }

		// In fact, it is the inclusion operators...
    bool operator >=(const Attribute &bs) const
    {
	    return (m_V & bs.m_V) == bs.m_V;
    }

    bool operator <=(const Attribute &bs) const
    {
	    return (m_V & bs.m_V) == m_V;
    }

    bool has_same_begin( const Attribute &attr ) const // Les 2 attr ont le meme debut
    {
        unsigned int a;
            // On cherche les premiers 2 bits differents (attributs differents)
        for ( a = 0; a < GetMaxAttribute( ); a++ )
            if ( contain( a ) != attr.contain( a ) )
                break;

            // On est sur 2 bits differents
        unsigned int j;
            // On verifie qu'il n'y a plus qu'un seul bit a 1
        for ( j = a; ( (j < GetMaxAttribute( )) && !contain( j ) ); j++ );
        for ( j++;   ( (j < GetMaxAttribute( )) && !contain( j ) ); j++ );

            // On a au moins 2 bits a 1 donc erreur
        if ( j < GetMaxAttribute( ) )
            return false;

            // On verifie qu'il n'y a plus qu'un seul bit a 1
        for ( j = a; ( (j < GetMaxAttribute( )) && !attr.contain( j ) ); j++ );
        for ( j++;   ( (j < GetMaxAttribute( )) && !attr.contain( j ) ); j++ );

            // On a au moins 2 bits a 1 donc erreur
        if ( j < GetMaxAttribute( ) )
            return false;

        return j == GetMaxAttribute( );
    }

};

inline std::ostream &operator<<(std::ostream &os, const Attribute &bs)
{
	for ( unsigned int i = 0; i < Attribute::GetMaxAttribute( ); ++i)
            if ( bs.m_V & (1 << i) )
                os << (char) ('A' + i);

	return os;
}


///////////////////////////////////////////////////////////////
#endif
