/**
*
*/
package photoSpreadUtilities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import photoSpreadObjects.PhotoSpreadObject;
/**
* @author paepcke
*
* Static class for generating PhotoSpread object
* comparators. Comparators are classes that implement
* interface Comparator for a particular type. Their
* main method is compare(o1, o2). An important use
* for this mechanism is to sort TreeSetRandomSubsetIterable and TreeMap
* structures.
*
* The code below consists of a static outer factory class,
* which offers createXXX() methods to return Comparator
* instances for sorting PhotoSpread objects by various
* criteria: UUID, and metadata content. Others could be
* added, such as image-based comparators.
*/
public class PhotoSpreadComparatorFactory {
public static Comparator<PhotoSpreadObject> createPSUUIDComparator() {
return new PhotoSpreadComparatorFactory().new UUIDComparator();
}
public static PhotoSpreadComparatorFactory.MetadataComparator createPSMetadataComparator() {
return new PhotoSpreadComparatorFactory().new MetadataComparator();
}
public static PhotoSpreadComparatorFactory.MetadataComparator createPSMetadataComparator(String metadataSortField) {
return new PhotoSpreadComparatorFactory().new MetadataComparator(metadataSortField);
}
/****************************************************
* Inner Class: Comparison by UUID
*****************************************************/
/**
* @author paepcke
*
* Comparator class for sorting PhotoSpreadObjects by UUID
*
*/
public class UUIDComparator implements Comparator<PhotoSpreadObject> {
/**
* Compares two PhotoSpreadObject's by
* their universally unique identifier (UUID).
*/
public UUIDComparator() {
}
/**
* Comparison operator for use by sorting. Compares the
* two passed-in objects by their UUID in alpha order.
*
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(PhotoSpreadObject o1, PhotoSpreadObject o2) {
return o1.getObjectID().compareTo(o2.getObjectID());
}
}
/****************************************************
* Inner Class: Comparison by metadata
*****************************************************/
/**
* @author paepcke
*
* Comparator class for sorting PhotoSpreadObjects by metadata.
* Up to three levels of sorting are possible.
*
*/
public class MetadataComparator implements Comparator<PhotoSpreadObject> {
Comparator<String> _stringComparatorCaseInsensitive = String.CASE_INSENSITIVE_ORDER;
ArrayList<String> _sortFldKeys = new ArrayList<String>();
public MetadataComparator() {
// For this comparator to compare based on metadata
// comparisons, user later needs to call addMetadataSortKey().
}
public MetadataComparator(String sortFld1Key) {
_sortFldKeys.add(sortFld1Key);
}
/****************************************************
* Methods inner class MetadataComparator
*****************************************************/
/** Adds new metadata search key at bottom of search key hierarchy
* @param newKey
*/
public void addMetadataSortKey (String newKey) {
_sortFldKeys.add(newKey);
}
/** Adds multiple sorted keys in equals() order to bottom of search key hierarchy
* @param newKeys
*/
public void addMetadataSortKey (Collection<String> newKeys) {
_sortFldKeys.addAll(newKeys);
}
/** Replaces given oldKey with newKey in the metadata key search hierarchy.
* If oldKey is not present in the existing sort hierarchy keys, just
* add oldKey to the bottom of the hierarchy.
*
* @param oldKey
* @param newKey
*/
public void replaceMetadataSortKey (String oldKey, String newKey) {
int place = _sortFldKeys.indexOf(oldKey);
if (place == Const.NOT_FOUND)
_sortFldKeys.add(newKey);
else
_sortFldKeys.set(place, newKey);
}
public void clearMetadataSortKeys () {
_sortFldKeys.clear();
}
/** Remove a metadata sort key from the sort hierarchy
* @param keyToDiscard
*/
public void removeMetadataSortKey (String keyToDiscard) {
int place = _sortFldKeys.indexOf(keyToDiscard);
if (place == Const.NOT_FOUND)
return;
else
_sortFldKeys.remove(place);
}
/**
* Workhorse: compare two PhotoSpreadObject instances
* (or subclasses of it). First comparison is by
* the metadata value of _sortFld1Key. If those values
* are equal, values for _sortFld2Key are compared, etc.
* down one more level.
*
* @param PhotoSpreadObject o1
* @param PhotoSpreadObject o2
* @return Negative number for o1 < o2; 0 for equal, positive number for o1 > o2
*/
public int compare(PhotoSpreadObject o1, PhotoSpreadObject o2) {
if (_sortFldKeys.isEmpty())
return o1.getObjectID().compareTo(o2.getObjectID());
int res;
String searchKey;
String metadataO1;
String metadataO2;
Iterator<String> it = _sortFldKeys.iterator();
while (it.hasNext()) {
searchKey = it.next();
metadataO1 = o1.getMetaData(searchKey);
metadataO2 = o2.getMetaData(searchKey);
// Compare the objs by this metadata field. Note
// that getMetaData() above returns the string
// Const.NULL_VALUE_STRING.
// if a requested metadata field is absent. We use the
// String class' built-in case insensitive comparator:
if (metadataO1.equalsIgnoreCase(Const.NULL_VALUE_STRING))
if (metadataO2.equalsIgnoreCase(Const.NULL_VALUE_STRING))
// Neither O1 nor O2 has a value for the metadata attribute:
return o1.getObjectID().compareTo(o2.getObjectID());
else
// O1 does not have a value for the metadata attribute,
// but O2 does. We 'prefer' O2: O1 > O2, i.e. O2 orders
// earlier than O1:
return Const.BIGGER;
else
if (metadataO2.equalsIgnoreCase(Const.NULL_VALUE_STRING))
// O1 has a value for the metadata attribute, but O2
// does not. We prefer O1: O1 < O2, i.e. O2 orders later
// than O1:
return Const.SMALLER;
else
// Both O1 and O2 have values for the metadata
// attributes. Compare the two values:
res = _stringComparatorCaseInsensitive.compare(metadataO1, metadataO2);
// Normalize return vals: -1 for less-than, +1 for greater-than.
// This way caller can use Const.BIGGER and Const.SMALLER on the
// return. (I dropped that nicety to gain speed during big sorts):
// if (res < 0) res = -1;
// if (res > 0) res = 1;
if (res != Const.EQUAL) return res;
// Objects are equal by this current metadata key's value. Loop
}
// Objects are equal by all of the search keys. So they are EQUAL:
return Const.EQUAL;
}
}
}