#include "DmGroup.h"

#define EmptyGroupSlot 0
#define dprintf if (debug) fprintf

DmGroup::SubGroup::SubGroup()
{
  id = dm_create_group();

  nItems = 0;
  changedBits = 0;
  
  for (int slot = 0; slot < MaxDmGroupSize; slot++)
    items[slot] = EmptyGroupSlot;
}


DmGroup::DmGroup()
{
  newSubGroup();
}


DmGroup::~DmGroup()
{
  SubGroup *subGroup;
  
  for (int i = 0; i < _subGroups.size(); i++)
  {
    _subGroups.get(i, &subGroup);
    dm_delete_group(subGroup->id);
    delete subGroup;
  }
}


DmGroup::SubGroup *DmGroup::newSubGroup()
{
  SubGroup *subGroup = new SubGroup();
  _subGroups.add(&subGroup);
  return subGroup;
} 


DmGroup::SubGroup *DmGroup::availableSubGroup()
{
  SubGroup *subGroup;

  for (int i = 0; i < _subGroups.size(); i++)
  {
    _subGroups.get(i, &subGroup);
    
    if (subGroup->nItems < MaxDmGroupSize)
      return subGroup;
  }

  // No empty slots. Need to create a new SubGroup
  return newSubGroup();
}


Errno DmGroup::addItem(DmObject *dmObject)
{
  return addItem(dmObject->getHandle());
}


Errno DmGroup::addItem(DM_Item dmItem)
{
  SubGroup *subGroup = availableSubGroup();

  DWord idBitMap;
  Errno err;
  
  if ((err = dm_group_add_item(subGroup->id, dmItem, &idBitMap)) != SUCCESS)
    return err;

  // Determine which slot was just filled, and put dmItem handle in it
  for (int slot = 0; slot < MaxDmGroupSize; slot++)
  {
    if (idBitMap & (01 << slot))
    {
      subGroup->items[slot] = dmItem;
      subGroup->nItems++;
      break;
    }
  }
  
  return SUCCESS;
}


Errno DmGroup::deleteItem(DmObject *dmObject)
{
  return deleteItem(dmObject->getHandle());
}


Errno DmGroup::deleteItem(DM_Item dmItem)
{
  Errno err;
  SubGroup *subGroup;
  MBool found = FALSE;
  
  for (int i = 0; i < _subGroups.size() && !found; i++)
  {
    _subGroups.get(i, &subGroup);
    for (int slot = 0; slot < MaxDmGroupSize; slot++)
    {
      if (subGroup->items[slot] == dmItem)
      {
	if ((err = dm_group_delete_item(subGroup->id, dmItem)) != SUCCESS)
	  return err;

	subGroup->nItems--;
	subGroup->items[slot] = EmptyGroupSlot;
	found = TRUE;
        // Want to delete ALL occurrences of this item, so continue searching
      }
    }
  }

  if (!found)
    return EDM_GENERAL;

  return SUCCESS;
}


MBool DmGroup::getChanges()
{
  SubGroup *subGroup;
  MBool debug = FALSE;
  MBool changes = FALSE;
  
  for (int i = 0; i < _subGroups.size(); i++)
  {
    _subGroups.get(i, &subGroup);
    if ((subGroup->changedBits = dm_get_group_changes(subGroup->id)) != 0)
      changes = TRUE;

    dprintf(stderr, "DmGroup::getChanges() - subGroup #%d, changedBits=%d\n",
	    i, subGroup->changedBits);
  }

  return changes;
}


MBool DmGroup::itemsChanged()
{
  SubGroup *subGroup;
  
  for (int i = 0; i < _subGroups.size(); i++)
  {
    _subGroups.get(i, &subGroup);
    if (subGroup->changedBits)
      return TRUE;
  }

  // Didn't find any changed items
  return FALSE;
}


MBool DmGroup::itemChanged(DmObject *dmObject)
{
  return itemChanged(dmObject->getHandle());
}


MBool DmGroup::itemChanged(DM_Item dmItem)
{
  SubGroup *subGroup;
  
  for (int i = 0; i < _subGroups.size(); i++)
  {
    _subGroups.get(i, &subGroup);
    
    if (subGroup->changedBits)
    {
      for (int slot = 0; slot < MaxDmGroupSize; slot++)
      {
	if ((01 << slot) & subGroup->changedBits)
	{
	  if (subGroup->items[slot] == dmItem)
	    return TRUE;
	}
      }
    }
  }
  return FALSE;
}


int DmGroup::nSubGroups()
{
  return _subGroups.size();
}


int DmGroup::nItems() 
{
  int total = 0;
  SubGroup *subGroup;
  for (int i = 0; i < nSubGroups(); i++) {
    _subGroups.get(i, &subGroup);
    total += subGroup->nItems;
  }
  return total;
}


DM_Item DmGroup::item(unsigned n)
{
  if (n >= nItems())
    return 0;

  SubGroup *subGroup;
  int index = 0;

  for (int i = 0; i < nSubGroups(); i++) {
    _subGroups.get(i, &subGroup);
    for (int j = 0; j < subGroup->nItems; j++) {

      if (index++ == n) 
	return subGroup->items[j];
    }
  }
  return 0;
}

