/***************************************************************************
 *   Copyright (C) 2003-2004 by Raphael Langerhorst                        *
 *   raphael-langerhorst@gmx.at                                            *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

#ifndef GELEMENTIDH
#define GELEMENTIDH

#include <qvaluelist.h>

class QString;

namespace GCS
{

/**
 * \class GIDRange GElementID.h
 * \brief A range of element IDs.
 *
 * Represents a range of element IDs, usually used
 * to store available free element IDs.
 * The range itself includes the bounds, that means
 * for example a range of 1 to 1 counts 1 while
 * 2 to 5 counts 5-2+1 = 4 possible IDs.
 * A range is considered to be empty as soon
 * as lower bound > upper bound.
 */
class GIDRange
{
  private:
    /**
     * Lower bound of the ID range.
     * The range includes the bounds themselves as well.
     */
    unsigned long LowerBound;

    /**
     * Upper bound of the ID range.
     * The range includes the bounds themselves as well.
     */
    unsigned long UpperBound;

  public:
    /**
     * Constructor (only for QValueList), initializes to 1 - 0.
     */
    GIDRange();

    /**
     * Constructor.
     */
    GIDRange(unsigned long lower_bound, unsigned long upper_bound);
    
    /**
     * @returns ID between LowerBound and UpperBound.
     * @returns 0 when no ID is available.
     */
    unsigned long takeID();

    /**
     * @return true when ID Range is empty.
     */
    bool isEmpty() const;

    /**
     * @return number of available IDs
     */
    unsigned long count() const;

    /**
     * Sets the range of IDs.
     */
    void setRange(unsigned long low, unsigned long high);

    /**
     * @return lower bound of the range.
     */
    unsigned long getLowerBound() const;

    /**
     * @return upper bound of the range.
     */
    unsigned long getUpperBound() const;
};

/**
 * \class GIDContainer GElementID.h
 * \brief A simple container for ranges of GElementIDs.
 */
class GIDContainer : public QValueList<GIDRange*>
{
  public:
    virtual ~GIDContainer() {}
};

/**
  \class GElementID GElementID.h
  \brief Provides unique identification for elements
  @author Raphael Langerhorst
  
  Do NOT use ID 0 for elements, it represents "no ID".
 
  @todo Add support for element ID observers, they should be notified when running low on IDs
*/

class GElementID
{  
  private:
    
    /**
      * The Container with all available free Element IDs.
      */
    static GIDContainer FreeIDs;
    
  public:

    /**
     * The returned ID is removed from storage.
     * @return the a free element ID
     */
    static GElementID getFreeID();

    /**
     * The returned IDs are removed from GElementID::FreeIDs.
     * @return a GIDContainer with desired amount of free IDs.
     */
    static GIDContainer getFreeIDRange(unsigned long amount);

    /**
     * Adds given range of element IDs to storage.
     */
    static void addFreeIDRange(unsigned long lower_bound, unsigned long upper_bound);

    /**
     * @return the total number of available free GElementIDs.
     */
    static unsigned long countFreeIDs();
    
  private:
  
    /**
     * The ID is represented by an unsigned long integer.
     */
    unsigned long ID;

  public:
    /**
     * DO NOT USE THIS CONSTRUCTOR!!!
     * 
     * For some reason QValueListNode requires a default constructor.
     * to avoid instantiation without a value everywhere else this
     * constructor is private.
     *
     * @todo This is a workaround and should be removed as soon as Qt
     * @todo does not depend on such a constructor for QValueList anymore.
     * 
     * @note looks like QMap depends on it as well, changed to public.
     */
    GElementID();
    
  public:
  
    /**
     * Public constructor initializes to given ID.
     */
    GElementID(unsigned long ID);

    /**
     * Copy constructor.
     */
    GElementID(const GElementID& original);

    /**
     * @return copy of the ID.
     */
    unsigned long getID() const;
    
    /**
     * @return id as string;
     */
    QString toString() const;

    /**
     * This enables comparing of element IDs.
     * @return true when both GElementID objects have the same ID.
     */
    bool operator==(const GElementID& id) const;
    
    /**
     * This enables comparing of element IDs.
     * @return true when both GElementID objects have different IDs.
     */
    bool operator!=(const GElementID& id) const;
    
    /**
     * This enables comparing of element IDs.
     * @return true when this element has a higher ID than compared element.
     */
    bool operator>(const GElementID& id) const;
    
    /**
     * This enables comparing of element IDs.
     * @return true when this element has a lower ID than compared element.
     */
    bool operator<(const GElementID& id) const;
    
    /**
     * This enables comparing of element IDs.
     * @return true when this element has a higher or equal ID than compared element.
     */
    bool operator>=(const GElementID& id) const;
    
    /**
     * This enables comparing of element IDs.
     * @return true when this element has a lower or equal ID than compared element.
     */
    bool operator<=(const GElementID& id) const;
    
    //this is a workaround because QValueListNode needs
    //a default constructor;
    //
    //this constructor is declared private in GElementID
    //and made only available to this class
    //
    //note: QValueListNode is used by QValueList
    
//     /**
//      * Gives QValueListNode access to the private default
//      * constructor - see GElementID() for details.
//      * 
//      */
//     friend class QValueListNode<GElementID>;
};

}

#endif
