/*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version. You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.aitools.programd.graph;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
/**
* This is an optimization of {@link Nodemapper} that avoids creating the internal {@link java.util.LinkedHashMap
* LinkedMap} until the number of mappings exceeds one (1).
*
* @author <a href="mailto:noel@aitools.org">Noel Bush</a>
*/
public class OneOptimalMemoryNodemapper extends AbstractNodemaster {
protected int size = 0;
protected String _key;
protected Object _value;
/**
* @see org.aitools.programd.graph.Nodemapper#containsKey(java.lang.String)
*/
@Override
public boolean containsKey(String key) {
if (this.size == 0) {
return false;
}
else if (this.size == 1) {
return key.equalsIgnoreCase(this._key);
}
return this.hidden.containsKey(key.toUpperCase());
}
/**
* @see org.aitools.programd.graph.Nodemapper#get(java.lang.String)
*/
@Override
public Object get(String key) {
if (this.size == 0) {
return null;
}
else if (this.size == 1) {
if (key.equalsIgnoreCase(this._key)) {
return this._value;
}
// (otherwise...)
return null;
}
else {
return this.hidden.get(key.toUpperCase());
}
}
/**
* @see org.aitools.programd.graph.Nodemapper#getAverageSize()
*/
@Override
public double getAverageSize() {
double total = 0d;
if (this.size == 1) {
if (this._value != null && this._value instanceof AbstractNodemaster) {
total = ((AbstractNodemaster) this._value).getAverageSize();
}
}
else {
for (Object object : this.hidden.values()) {
if (object instanceof AbstractNodemaster) {
total += ((AbstractNodemaster) object).getAverageSize();
}
}
}
if (this._parent != null) {
return (this.size + total / this.size) / 2d;
}
// otherwise...
return total / this.size;
}
/**
* @see org.aitools.programd.graph.Nodemapper#keySet()
*/
@Override
public Set<String> keySet() {
if (this.size == 1) {
Set<String> result = new HashSet<String>();
if (this._key != null) {
result.add(this._key);
}
return result;
}
// (otherwise...)
return this.hidden.keySet();
}
/**
* @see org.aitools.programd.graph.Nodemapper#put(java.lang.String, java.lang.Object)
*/
@Override
public Object put(String key, Object value) {
if (this.size == 0) {
this._key = key.toUpperCase().intern();
if (value instanceof String) {
this._value = ((String) value).intern();
}
else {
this._value = value;
}
this.size = 1;
return this._value;
}
else if (this.size == 1) {
this.hidden = new LinkedHashMap<String, Object>();
this.hidden.put(this._key, this._value);
this._key = null;
this._value = null;
this.size = 2;
if (value instanceof String) {
return this.hidden.put(key.toUpperCase().intern(), ((String) value).intern());
}
// otherwise...
return this.hidden.put(key.toUpperCase().intern(), value);
}
else {
this.size++;
if (value instanceof String) {
return this.hidden.put(key.toUpperCase().intern(), ((String) value).intern());
}
// otherwise...
return this.hidden.put(key.toUpperCase().intern(), value);
}
}
/**
* @see org.aitools.programd.graph.Nodemapper#remove(java.lang.Object)
*/
@Override
public void remove(Object value) {
if (this.size == 1) {
if (value.equals(this._value)) {
this._value = null;
this._key = null;
}
else {
// We didn't find a key.
Logger.getLogger("programd.graphmaster").error(
String.format("Key was not found for value when trying to remove \"%s\".", value));
return;
}
this.size = 0;
}
else if (this.size > 1) {
// Find the key for this value.
Object keyToRemove = null;
for (Map.Entry<String, Object> item : this.hidden.entrySet()) {
if (item.getValue().equals(value)) {
// Found it.
keyToRemove = item.getKey();
break;
}
}
if (keyToRemove == null) {
// We didn't find a key.
Logger.getLogger("programd.graphmaster").error(
String.format("Key was not found for value when trying to remove \"%s\".", value));
return;
}
if (this.size > 2) {
// Remove the value from the HashMap (ignore the primary
// value/key pair).
this.hidden.remove(keyToRemove);
this.size--;
}
// otherwise it is exactly 2...
else {
// Remove this item from the HashMap.
this.hidden.remove(keyToRemove);
// Set the last item in the HashMap to be the primary value/key
// pair for this Nodemapper.
this._key = this.hidden.keySet().iterator().next();
this._value = this.hidden.remove(this._key);
// Remove the empty HashMap to save space.
this.hidden = null;
this.size = 1;
}
}
else
// if (this.size == 0)
{
// We didn't find a key.
Logger.getLogger("programd.graphmaster").error(
String.format("No keys in Nodemapper when trying to remove \"%s\".", value));
}
}
/**
* @see org.aitools.programd.graph.Nodemapper#size()
*/
@Override
public int size() {
return this.size;
}
}