/***************************************************************************
 *   Copyright (C) 2004 - 2005 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.                                       *
 ***************************************************************************/

#include "GElementID.h"

#include <qstring.h>

namespace GCS
{

/**
 * The actual static instance in memory.
 */
GIDContainer GElementID::FreeIDs;


GIDRange::GIDRange()
: LowerBound(1),
  UpperBound(0)
{
}

GIDRange::GIDRange(unsigned long lower_bound, unsigned long upper_bound)
: LowerBound(lower_bound),
  UpperBound(upper_bound)
{
  //lower bound should NEVER be 0, the 0 IDs are not valid.
  if (LowerBound <= 0)
  {
    qWarning("Never use 0 as a valid GElementID, raised lower bound to 1!");
    LowerBound = 1;
  }
}

unsigned long GIDRange::takeID()
{
  if (isEmpty())
    return 0;
  return LowerBound++;
}

bool GIDRange::isEmpty() const
{
  if (count() <=0)
    return true;
  return false;
}

unsigned long GIDRange::count() const
{
  if (LowerBound > UpperBound)
    return 0;
  else
    return UpperBound - LowerBound + 1;
}

void GIDRange::setRange(unsigned long low, unsigned long high)
{
  LowerBound = low;
  UpperBound = high;
}

unsigned long GIDRange::getLowerBound() const
{
  return LowerBound;
}

unsigned long GIDRange::getUpperBound() const
{
  return UpperBound;
}

GElementID GElementID::getFreeID()
{
  unsigned long id = 0;
  while (!FreeIDs.isEmpty() && id==0)
  {
    GIDRange* first = FreeIDs.first();
    if (first->isEmpty())
      FreeIDs.pop_front();
    else
      id = first->takeID();
  }
  return GElementID(id);
}

GIDContainer GElementID::getFreeIDRange(unsigned long amount)
{
  GIDContainer container;
  unsigned long count = 0;
  while (!FreeIDs.isEmpty() && amount - count > 0)
  {
    GIDRange* first = FreeIDs.first();
    unsigned long count_first = first->count();
    if (amount - count >= count_first)
    {
      container.append(new GIDRange(*first));
      FreeIDs.pop_front();
      count += count_first;
    }
    else if (amount - count < count_first)
    {
      unsigned long low = first->getLowerBound();
      first->setRange(low+amount-count,first->getUpperBound());
      container.append(new GIDRange(low,low+amount-count-1));  //lower and upper bounds are included in count!
      count = amount;  //MUST equal count += amount - count;
    }
  }
  return container;
}

void GElementID::addFreeIDRange(unsigned long lower_bound, unsigned long upper_bound)
{
  qDebug(QString("Element ID Range added to free IDs: %1 to %2").arg(QString::number(lower_bound)).arg(QString::number(upper_bound)));
  FreeIDs.append(new GIDRange(lower_bound,upper_bound));
}

unsigned long GElementID::countFreeIDs()
{
  unsigned long c = 0;
  GIDContainer::iterator it;
  for (it = FreeIDs.begin(); it != FreeIDs.end(); ++it)
  {
    c+=(*it)->count();
  }
  return c;
}

GElementID::GElementID()
: ID(0)
{
}

GElementID::GElementID(unsigned long id)
: ID(id)
{
}

GElementID::GElementID(const GElementID& original)
: ID(original.getID())
{
}

unsigned long GElementID::getID() const
{
  return ID;
}

QString GElementID::toString() const
{
  return QString::number(ID);
}

bool GElementID::operator==(const GElementID& id) const
{
  return this->ID == id.ID ? true : false;
}

bool GElementID::operator!=(const GElementID& id) const
{
  return this->ID != id.ID ? true : false;
}

bool GElementID::operator>(const GElementID& id) const
{
  return this->ID > id.ID ? true : false;
}

bool GElementID::operator<(const GElementID& id) const
{
  return this->ID < id.ID ? true : false;
}

bool GElementID::operator>=(const GElementID& id) const
{
  return this->ID >= id.ID ? true : false;
}

bool GElementID::operator<=(const GElementID& id) const
{
  return this->ID <= id.ID ? true : false;
}

}


syntax highlighted by Code2HTML, v. 0.9.1