/**
*
*/
package photoSpreadUtilities;
import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import photoSpread.PhotoSpreadException;
import photoSpreadUtilities.Misc.Pair;
/**
* @author paepcke
*
*/
public class PhotoSpreadProperties<KeyType, ValueType> {
private static final int defaultExpectedNumEntries = 20;
private Hashtable<KeyType, ValueType> _theHashTable;
private PhotoSpreadProperties<KeyType, ValueType> _theDefaults;
/****************************************************
* Constructor(s)
*****************************************************/
public PhotoSpreadProperties(PhotoSpreadProperties<KeyType, ValueType> defaults, int expectedNumEntries) {
_theHashTable = new Hashtable<KeyType, ValueType>((int) (expectedNumEntries / .75));
_theDefaults = defaults;
}
public PhotoSpreadProperties(PhotoSpreadProperties<KeyType, ValueType> defaults) {
this(defaults, defaultExpectedNumEntries);
}
public PhotoSpreadProperties(int expectedNumEntries) {
this(null, expectedNumEntries);
}
public PhotoSpreadProperties() {
this(null, defaultExpectedNumEntries);
}
/****************************************************
* Methods
*****************************************************/
public void put (KeyType key, ValueType value) {
_theHashTable.put(key, value);
}
public ValueType get (KeyType key) {
ValueType res = _theHashTable.get(key);
if (res != null)
return res;
else
if (_theDefaults != null)
return _theDefaults.get(key);
else
return null;
}
public void setProperty (KeyType key, ValueType value) {
put (key, value);
}
public ValueType getProperty (KeyType key) {
return get(key);
}
public Enumeration<KeyType> keys() {
return _theHashTable.keys();
}
/**
* Given a user preferences key whose value is
* expected to be an int, return that int.
* Key existence and integer type checking is done.
*
* @param userPrefsKey
* @return User preference (an integer)
*/
public Integer getInt(KeyType userPrefsKey) {
int res;
String thePrefIfAString;
int thePrefIfAnInt;
try {
thePrefIfAString = ((String) get(userPrefsKey));
if (thePrefIfAString == null)
return null;
} catch (ClassCastException eNotAString) {
try {
thePrefIfAnInt = ((Integer) get(userPrefsKey));
return thePrefIfAnInt;
} catch (ClassCastException eNotAnInt) {
throw new RuntimeException(new PhotoSpreadException.IllegalPreferenceValueException (
"Preference value '" +
userPrefsKey +
"' is not a string or integer."));
}
}
if (thePrefIfAString == null) {
return null;
}
try {
res = Integer.parseInt(thePrefIfAString.trim());
} catch (NumberFormatException e) {
throw new RuntimeException(new PhotoSpreadException.IllegalPreferenceValueException(
"Expected an integer for user preference '" +
userPrefsKey +
"'. Was given '" +
thePrefIfAString +
"' instead."));
}
return res;
}
/**
* Given a key into the user preferences, expect that the
* entry contains two integers that correspond to some width and
* height. We return a respective Dimension object.
* Exception NotBoundException if property not found.
* Exception NumberFormatException if property value is not
* a string of two, space-separated integers.
*
* @param userPrefsKey
* @return
*/
public Dimension getDimension(KeyType userPrefsKey) {
Pair<Integer, Integer> widthHeight = null;
Dimension valIsDimension = null;
// Get the requested user preference value:
try {
valIsDimension = (Dimension) get(userPrefsKey);
return valIsDimension;
} catch (ClassCastException eNotAString) {
try {
ValueType pref = get(userPrefsKey);
if (pref == null)
return null;
widthHeight = twoIntsFromString (pref);
return new Dimension((int) widthHeight.first(), (int) widthHeight.second());
} catch (ClassCastException eNotAnInt) {
throw new RuntimeException(new PhotoSpreadException.IllegalPreferenceValueException (
"Preference value '" +
userPrefsKey +
"' is not a string or Dimension instance."));
}
}
}
/**
* Given a string with two integers, produce a Pair object
* with the two integers. Error checking is performed on
* the string.
*
* @param strOfTwoSpaceSeparatedInts
* @return Pair object containing two ints.
*/
public Pair<Integer, Integer> twoIntsFromString (ValueType twoIntsStr) {
String strOfTwoSpaceSeparatedInts = ((String) twoIntsStr);
// Partition the string by whitespace. The 3 tells the
// split to return at most 3 elements: the first two
// (hopefully) numbers, and any rest of the string. The
// latter we ignore:
String[] intStrArray = strOfTwoSpaceSeparatedInts.split("[ \t\n\f\r]", 3);
if (intStrArray.length < 2) {
throw new NumberFormatException("Expected a string with two integers. Was given '" +
strOfTwoSpaceSeparatedInts + "'.");
}
int first, second = 0;
try {
first = Integer.parseInt(intStrArray[0]);
second = Integer.parseInt(intStrArray[1]);
} catch (NumberFormatException e) {
throw new RuntimeException(new NumberFormatException("Expected a string with two integers. Was given '" +
strOfTwoSpaceSeparatedInts + "'."));
}
return new Misc().new Pair<Integer, Integer>(first, second);
}
public void load (BufferedReader inStream)
throws IOException {
String propName = "";
// Kludge to save me work:
Properties loadPropsCrutch = new Properties();
loadPropsCrutch.load(inStream);
Enumeration propNames = loadPropsCrutch.propertyNames();
while (propNames.hasMoreElements()) {
propName = (String) propNames.nextElement();
put((KeyType) propName, (ValueType) loadPropsCrutch.getProperty(propName));
}
}
public void store (FileWriter outStream, String comments)
throws IOException {
KeyType propName = null;
Enumeration<KeyType> hashKeys = _theHashTable.keys();
// Kludge to save me work:
Properties savePropsCrutch = new Properties();
while (hashKeys.hasMoreElements()) {
propName = (KeyType) hashKeys.nextElement();
savePropsCrutch.put(propName, get(propName));
}
savePropsCrutch.store(outStream, comments);
}
public void loadFromXML (InputStream inStream)
throws IOException {
String propName = "";
// Kludge to save me work:
Properties loadPropsCrutch = new Properties();
loadPropsCrutch.loadFromXML(inStream);
Enumeration<String> propNames = (Enumeration<String>) loadPropsCrutch.propertyNames();
while (propNames.hasMoreElements()) {
propName = (String) propNames.nextElement();
put((KeyType) propName, (ValueType) loadPropsCrutch.getProperty(propName));
}
}
public void storeToXML (OutputStream outStream, String comments)
throws IOException {
KeyType propName = null;
Enumeration<KeyType> hashKeys = _theHashTable.keys();
// Kludge to save me work:
Properties savePropsCrutch = new Properties();
while (hashKeys.hasMoreElements()) {
propName = (KeyType) hashKeys.nextElement();
savePropsCrutch.put(propName, get(propName));
}
savePropsCrutch.storeToXML(outStream, comments);
}
}