/*
* TreeSetGreedy.java, special container for managing z-Indexes of traces in jchart2d.
* Copyright (C) 2004 - 2011 Achim Westermann.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* If you modify or optimize the code in a useful way please let me know.
* Achim.Westermann@gmx.de
*
*/
package info.monitorenter.util.collections;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* A <code>Set</code> that will always successfully add new instances and
* guarantee that all the "<em>Comparable properties</em>" of the contained
* <code>{@link info.monitorenter.util.collections.IComparableProperty}</code>
* instances will build a set (no duplicates).
* <p>
* Although the interface of {@link java.util.Set} is preserved and allows
* adding any <code>Object</code> <b>only
* {@link info.monitorenter.util.collections.IComparableProperty} instances may
* be added to <code>TreeSetGreedy</code> </b> because it uses a proprietary
* {@link java.util.Comparator}.
* <p>
* The added <code>IComparableProperty</code> instances with the lowest
* {@link java.lang.Number} property (see
* {@link info.monitorenter.util.collections.IComparableProperty#getComparableProperty()}
* ) will be returned first from the retrievable <code>Iterator</code>
* <p>
* <h2>Warning</h2>
* If the <code>IComparableProperty</code> (thus meaning the member or accessed
* data) is changed from outside, the internal order of this set will get
* corrupted and iterations or add/remove calls may fail. Therefore it is
* necessary to remove the instance before outside modification and later on add
* it again.
* <p>
*
* @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
*
* @param <T>
* the type of instances to store.
*/
public class TreeSetGreedy<T extends IComparableProperty> extends TreeSet<T> implements Set<T> {
/**
* A <code>Comparator</code> that will compare {@link IComparableProperty}
* instances by their {@link IComparableProperty#getComparableProperty()}
* number.
* <p>
*
* @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann </a>
*
* @param <T>
* the type of instances to compare.
*/
private static final class NumberPropertyComparator<T extends IComparableProperty> implements
Comparator<T>, Serializable {
/** Generated <code>serialVersionUID</code>. */
private static final long serialVersionUID = 2279828650090806643L;
/**
* Defcon.
* <p>
*/
public NumberPropertyComparator() {
// nop
}
/**
* Compares two Objects by casting them to {@link IComparableProperty} and
* using their {@link IComparableProperty#getComparableProperty()} property.
* <p>
* This <code>Comparator</code> may only be used in {@link java.util.Set}
* instances that only contain <code>IComparableProperty</code> instances.
* <p>
* For two instances that are judged equal (equal z-index) the first
* argument is decided to stay, the second instance gets assigned a higher
* {@link IComparableProperty#setComparableProperty(Number)} by one, then is
* removed from the <code>Set</code> it is working for and added anew thus
* getting the next index order.
* <p>
* This procedure is expensive (performs <em>O(n!)</em>) but easy to
* implement and guarantees that every <code>IComparableProperty</code>
* instance is added (never returns 0), all instances have a different
* values and the newest added instances definetely get their chosen value.
* <p>
*
* @param o1
* the first instance for comparison.
*
* @param o2
* the second instance for comparison.
*
* @throws ClassCastException
* if one of the given arguments does not implement
* {@link IComparableProperty}
*
* @return -1 if o1 is first, 0, if both are equal and +1 if o1 comes last.
*
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(final T o1, final T o2) throws ClassCastException {
int result;
// Don't take real identical elements (set policy)
if (o1 == o2) {
result = 0;
} else {
double i1 = o1.getComparableProperty().doubleValue();
double i2 = o2.getComparableProperty().doubleValue();
// fake and take equal elements.
if (i1 < i2) {
result = -1;
} else if (i1 == i2) {
result = 0;
} else {
result = 1;
}
}
return result;
}
}
/**
* Generated <code>serialVersionUID</code>.
*/
private static final long serialVersionUID = 3258130237048173623L;
/**
* Creates a new number of the correct type increased by 1.
* <p>
*
* @param n
* the number to increase.
*
* @return a new number of the correct type increased by 1.
*/
private static Number createDecreasedNumber(final Number n) {
Number result;
Class< ? > c = n.getClass();
if (c == Integer.class) {
result = new Integer(n.intValue() - 1);
} else if (c == Double.class) {
result = new Double(n.doubleValue() - 1);
} else if (c == Float.class) {
result = new Float(n.floatValue() - 1);
} else if (c == Short.class) {
result = new Short((short) (n.shortValue() - 1));
} else if (c == Byte.class) {
result = new Byte((byte) (n.byteValue() - 1));
} else if (c == Long.class) {
result = new Long(n.longValue() - 1);
} else if (c == BigDecimal.class) {
BigDecimal bd = new BigDecimal(n.toString());
bd = bd.subtract(new BigDecimal(1));
result = bd;
} else {
BigInteger bi = new BigInteger(n.toString());
bi = bi.subtract(new BigInteger("1"));
result = bi;
}
return result;
}
/**
* Creates an instance with an internal <code>Comparator</code> to fulfill the
* contract of this class.
*/
public TreeSetGreedy() {
super(new NumberPropertyComparator<IComparableProperty>());
}
/**
* Attempts to add the the given <code>T</code>.
* <p>
*
* @param o
* the T to add.
* @return see superclass.
* @see java.util.TreeSet#add(java.lang.Object)
*/
@Override
public synchronized boolean add(final T o) {
boolean ret = this.addInternal(o);
// this.packComparableProperties();
return ret;
}
/**
* Internally adds the given instance.
* <p>
*
* @param o
* the instance to add.
*
* @return true if the instance was added.
*/
private boolean addInternal(final T o) {
if (!this.isEmpty()) {
// check if we have to manipulate the order to be able to store the
// element.
// Policy is: never change comparable property if it is avoidable!
boolean alreadyThrere = this.contains(o);
if (alreadyThrere) {
T first = this.first();
o.setComparableProperty(TreeSetGreedy.createDecreasedNumber(first.getComparableProperty()));
}
}
boolean ret = super.add(o);
return ret;
}
/**
* @see java.util.TreeSet#remove(java.lang.Object)
*/
@Override
public boolean remove(final Object o) {
boolean result = super.remove(o);
return result;
}
/**
* Modifies the values of the comparable properties of the contained elements
* to have a continuous order of increasing integer values.
* <p>
* As the real value of the comparable property is unimportant for this set
* but only the relation of the values (order) is of interest this method may
* change all values to use only the minimum integer range for expressing the
* order.
* <p>
* An example of the procedure:
*
* <pre>
* [0, 10, 11, 22] -> [0,1,2,3]
* </pre>
*
* <p>
* This method allows to avoid exceeding bounds (e.g. between {
* {@link info.monitorenter.gui.chart.ITrace2D#Z_INDEX_MIN} and
* {@link info.monitorenter.gui.chart.ITrace2D#ZINDEX_MAX}) and allows that
* changes of the comparable properties always have an effect. If in the
* example above the 2nd instance would increase it's property by one from 10
* to 11 nothing would happen to the order.
* <p>
*
*/
// private void packComparableProperties() {
// int i = ITrace2D.ZINDEX_MAX;
// for (IComparableProperty prop : this) {
// prop.setComparableProperty(new Integer(i));
// i++;
// }
// }
}