package rescuecore2.worldmodel;
import static rescuecore2.misc.EncodingTools.writeInt32;
import static rescuecore2.misc.EncodingTools.writeProperty;
import static rescuecore2.misc.EncodingTools.readInt32;
import static rescuecore2.misc.EncodingTools.readProperty;
import java.util.Set;
import java.util.HashSet;
import java.util.Collection;
import java.util.Iterator;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
/**
Abstract base class for concrete Entity implementations.
*/
public abstract class AbstractEntity implements Entity {
private final EntityID id;
private final Set<EntityListener> listeners;
private final Set<Property> properties;
/**
Construct an AbstractEntity with a set of properties.
@param id The ID of this entity.
*/
protected AbstractEntity(EntityID id) {
this.id = id;
listeners = new HashSet<EntityListener>();
properties = new HashSet<Property>();
}
/**
AbstractEntity copy constructor.
@param other The AbstractEntity to copy.
*/
protected AbstractEntity(AbstractEntity other) {
this(other.getID());
}
@Override
public void addEntityListener(EntityListener l) {
synchronized (listeners) {
listeners.add(l);
}
}
@Override
public void removeEntityListener(EntityListener l) {
synchronized (listeners) {
listeners.remove(l);
}
}
@Override
public Entity copy() {
Entity result = copyImpl();
for (Property original : getProperties()) {
Property copy = result.getProperty(original.getURN());
copy.takeValue(original);
}
return result;
}
/**
Create a copy of this entity. Property values do not need to be copied.
@return A new Entity of the same type as this and with the same ID.
*/
protected abstract Entity copyImpl();
@Override
public final Set<Property> getProperties() {
return properties;
}
@Override
public Property getProperty(String propertyURN) {
return null;
}
@Override
public EntityID getID() {
return id;
}
@Override
public void write(OutputStream out) throws IOException {
int count = 0;
for (Property next : getProperties()) {
if (next.isDefined()) {
++count;
}
}
writeInt32(count, out);
for (Property next : getProperties()) {
if (next.isDefined()) {
writeProperty(next, out);
}
}
}
@Override
public void read(InputStream in) throws IOException {
int count = readInt32(in);
for (int i = 0; i < count; ++i) {
Property prop = readProperty(in);
if (prop == null) {
continue;
}
Property existing = getProperty(prop.getURN());
existing.takeValue(prop);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(getEntityName());
result.append(" (");
result.append(id);
result.append(")");
return result.toString();
}
/**
Get the full description of this object.
@return The full description.
*/
public String getFullDescription() {
StringBuilder result = new StringBuilder();
String name = getEntityName();
String urn = getURN();
if (!name.equals(urn)) {
result.append(name);
result.append(" [");
result.append(urn);
result.append("]");
}
else {
result.append(name);
}
result.append(" (");
result.append(id);
result.append(") [");
for (Iterator<Property> it = getProperties().iterator(); it.hasNext();) {
result.append(it.next().toString());
if (it.hasNext()) {
result.append(", ");
}
}
result.append("]");
return result.toString();
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
if (o instanceof AbstractEntity) {
// CHECKSTYLE:OFF:IllegalType
AbstractEntity a = (AbstractEntity)o;
// CHECKSTYLE:ON:IllegalType
return this.id.equals(a.id);
}
return false;
}
/**
Get the name of this entity. Default implementation returns the entity URN.
@return The name of this entity.
*/
protected String getEntityName() {
return getURN();
}
/**
Register a set of properties.
@param props The properties to register.
*/
protected void registerProperties(Property... props) {
for (Property p : props) {
properties.add(p);
if (p instanceof AbstractProperty) {
((AbstractProperty)p).setEntity(this);
}
}
}
/**
Notify all listeners that a property has changed.
@param p The changed property.
@param oldValue The old value.
@param newValue The new value.
*/
protected void firePropertyChanged(Property p, Object oldValue, Object newValue) {
Collection<EntityListener> copy;
synchronized (listeners) {
copy = new HashSet<EntityListener>(listeners);
}
for (EntityListener next : copy) {
next.propertyChanged(this, p, oldValue, newValue);
}
}
}