package ecologylab.collections;
import java.util.Collection;
import java.util.Iterator;
import ecologylab.generic.Debug;
import ecologylab.generic.StringBuilderBaseUtils;
/**
* Prioritized pools are a data structure containing an array of <code>T extends WeightSet</code><br>
* These sets are ordered in the list by priority. The main function of this data structure is to allow
* selections of elements from the list of pools, in order of priority. External calls to the pools object
* can call a maxSelect regardless of what internal weightSet is being called.
*
* @author damaraju
*
* @param <T> where T extends WeightSet
* @param <E> WeightSet is parameterized with E, where E extends SetElement.
*/
public class PrioritizedPool<E extends SetElement>
extends Debug implements Iterable<E>, Collection<E>
{
/**
* Beware of accesses outside PrioritizedPool. Use with caution.
* Ensure that any additions in fact belong to the right WeightSet in this array.
*/
protected WeightSet<E>[] weightSets;
public PrioritizedPool()
{
super();
}
public PrioritizedPool(WeightSet<E>[] weightSets)
{
this();
this.weightSets = weightSets;
}
public synchronized E maxPeek(int index)
{
int thisSize = this.size();
if(index >= thisSize || thisSize == 0)
return null;
for(int poolIndex = 0; poolIndex < this.numWeightSets(); poolIndex++)
{
WeightSet<E> weightSet = weightSets[poolIndex];
int weightSetSize = weightSet.size();
if(index >= weightSetSize)
{
index -= weightSetSize;
continue; //index is beyond this pool
}
return weightSet.maxPeek(index);
}
//Nothing found :(
return null;
}
public synchronized E maxSelect(boolean prune)
{
if(this.size() == 0)
return null;
else
{
//Prune all weightSets if we're in prune mode.
if(prune)
for(WeightSet<E> weightSet : weightSets)
weightSet.prune();
for(WeightSet<E> weightSet : weightSets)
{
if(weightSet.isEmpty())
continue;
else
return weightSet.maxSelect();
}
}
return null;
}
public synchronized E pruneAndMaxSelect()
{
return maxSelect(true);
}
public synchronized void clear(boolean doRecycleElements)
{
for(WeightSet<E> weightSet : weightSets)
weightSet.clear(doRecycleElements);
}
@Override
public int size()
{
int size = 0;
for(WeightSet<E> weightSet : weightSets)
size += weightSet.size();
return size;
}
public int maxSize()
{
int result = 0;
for (WeightSet<E> weightSet : weightSets)
{
int size = weightSet.size();
if (size > result)
result = size;
}
return result;
}
/**
* Inserts element into a set of the given priority.
* @param element
* @param priority
*/
public synchronized boolean insert(E element, int priority)
{
if(priority >= weightSets.length || priority < 0)
debug("invalid priority for Prioritized Pools (" + weightSets.length + ") : " + priority);
WeightSet<E> weightSet = weightSets[priority];
if(weightSet == null)
{
debug("no pool exists with priority: " + priority);
return false;
}
return weightSet.insert(element);
}
/**
*
* @return Mean of weights of the pools
*/
public synchronized float mean()
{
int poolTotalSize = 0;
float meanSum = 0;
for(WeightSet<E> weightSet : weightSets)
{
int poolSize = weightSet.size();
meanSum += poolSize * weightSet.mean();
poolTotalSize += poolSize;
}
if (poolTotalSize == 0)
return 0;
return meanSum / poolTotalSize;
}
public void pause()
{
for (WeightSet<E> weightSet : weightSets)
if(weightSet.isRunnable())
((RunnablePool) weightSet).pause();
}
public void unpause()
{
for (WeightSet<E> weightSet : weightSets)
if(weightSet.isRunnable())
((RunnablePool) weightSet).unpause();
}
public void stop()
{
for (WeightSet<E> weightSet : weightSets)
if(weightSet.isRunnable())
((RunnablePool) weightSet).stop();
}
public void start()
{
for(WeightSet<E> weightSet : weightSets)
if(weightSet.isRunnable())
((RunnablePool) weightSet).start();
}
public void toggleCollectingAgent()
{
for(WeightSet<E> weightSet : weightSets)
if(weightSet.isRunnable())
((RunnablePool) weightSet).toggleCollectingAgent();
}
/**
*
* @return Debug output that includes the size of each Set in this pool.
*/
public String countsString()
{
StringBuilder buffy = StringBuilderBaseUtils.acquire();
for(int i = 0; i < weightSets.length; i++)
{
buffy.append('[').append(i).append("]: ").append(weightSets[i].size()).append(' ');
}
String result = buffy.toString();
StringBuilderBaseUtils.release(buffy);
return result;
}
/**
* Remove an element from all the Sets in this pool.
* @param el
*/
public synchronized boolean remove(E el)
{
boolean result = false;
for(WeightSet<E> weightSet : weightSets)
result |= weightSet.remove(el);
return result;
}
public WeightSet<E> getWeightSet(int poolNum)
{
if (poolNum >= weightSets.length)
return null;
return weightSets[poolNum];
}
public WeightSet<E>[] getWeightSets()
{
return weightSets;
}
public int numWeightSets()
{
return weightSets.length;
}
@Override
public boolean isEmpty()
{
for(WeightSet<E> weightSet : weightSets)
if(!weightSet.isEmpty())
return false; //If not empty, return false and stop iteration.
return true; //Reaches here only if all weightsets are empty
}
@Override
public Iterator<E> iterator()
{
// TODO Auto-generated method stub
return new PoolIterator();
}
final class PoolIterator implements Iterator<E>
{
protected Iterator<E>[] weightSetIterators;
int idx = 0;
public PoolIterator()
{
weightSetIterators = new Iterator[weightSets.length];
int i=0;
for(WeightSet<E> weightSet : weightSets)
weightSetIterators[i++] = weightSet.iterator();
}
@Override
public boolean hasNext()
{
// no more pools to iterate through
if (idx >= weightSetIterators.length)
return false;
// go to the next pool if this one is empy
while (!weightSetIterators[idx].hasNext())
if (++idx >= weightSetIterators.length)
return false;
// return hasNext
return weightSetIterators[idx].hasNext();
}
@Override
public E next()
{
if (idx >= weightSetIterators.length)
return null;
E next = weightSetIterators[idx].next();
if (next == null)
{
idx++;
return next();
}
else
return next;
}
@Override
public void remove()
{
// does nothing
}
}
@Override
public boolean add(E e)
{
return insert(e, 0);
}
@Override
public boolean addAll(Collection<? extends E> c)
{
boolean result = false;
for (E element : c)
result |= add(element);
return result;
}
@Override
public void clear()
{
clear(false);
}
@Override
public boolean contains(Object o)
{
for (WeightSet<E> weightSet : weightSets)
{
if (weightSet.contains(o))
return true;
}
return false;
}
@Override
public boolean containsAll(Collection<?> c)
{
boolean result = false;
for (Object element : c)
{
for (WeightSet<E> weightSet : weightSets)
{
if (!weightSet.contains(element))
return false;
}
}
return true;
}
@Override
public boolean remove(Object arg0)
{
return remove((E) arg0);
}
@Override
public boolean removeAll(Collection<?> c)
{
boolean result = false;
for (Object o : c)
result |= remove(o);
return result;
}
@Override
public boolean retainAll(Collection<?> c)
{
throw new RuntimeException("not implemented.");
}
@Override
public Object[] toArray()
{
E[] result = (E[]) new SetElement[size()];
toArray(result);
return result;
}
/**
* @param result
*/
protected void toArray(E[] result)
{
int start = 0;
for (WeightSet<E> weightSet : weightSets)
{
weightSet.toArray(result, start);
start += weightSet.size();
}
}
@Override
public <T> T[] toArray(T[] input)
{
E[] result = (E[]) input;
if (result.length < size())
result = (E[]) toArray();
return (T[]) result;
}
}