package context.arch.storage;
import context.arch.comm.DataObject;
import context.arch.comm.DataObjects;
import context.arch.discoverer.Discoverer;
import context.arch.discoverer.component.AbstractElement;
import context.arch.storage.AttributeNameValue;
import context.arch.storage.Attributes;
/**
* This class is a container for an attribute name, value and type.
* TODO: how to handle characteristics such as: possible nominal values, min/max range?
*/
public class AttributeNameValuePin<T extends Comparable<? super T>> extends AttributeNameValue<T> {
protected int pin;
protected String pinType;
public static final String ANALOG = "analog";
public static final String DIGITAL = "digital";
public static final String ATTRIBUTE_NAME_VALUE_PIN = "attributeNameValuePin";
public static final String ATTRIBUTE_PIN = "attributePin";
public static final String ATTRIBUTE_PIN_TYPE = "attributePinType";
/**
* Constructor that takes only a name, pin and pinType
*
* @param name Name of attribute to store
*/
public AttributeNameValuePin(String name, Class<T> type, Integer pin, String pinType) {
super(name, type);
this.pin = pin;
this.pinType = pinType;
}
@SuppressWarnings("unchecked")
public AttributeNameValuePin(String name, T value, Integer pin, String pinType) {
this(name, (Class<T>)value.getClass(), value, pin, pinType);
}
/**
* Constructor that takes a name, value, type, pin and pinType
*
* @param name Name of attribute to store
* @param value Value of attribute to store
* @param type Datatype of attribute to store
* @param pin Pin of attribute to arduino
* @param pinType PinType of attribute to arduino
*/
public AttributeNameValuePin(String name, Class<T> type, T value, Integer pin, String pinType) {
super(name, type, value);
this.pin = pin;
this.pinType = pinType;
}
public AttributeNameValuePin(String name, Class<T> type, T value, Integer pin, String pinType, Attributes subAttributes) {
this(name, type, value, pin, pinType);
this.subAttributes = subAttributes;
}
/**
* Allows to dynamically (at runtime) instantiate a AttributeNameValue with the
* corresponding generic type.
* @param <T>
* @param name
* @param value
* @param pin
* @param pinType
* @return
*/
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> instance(String name, T value, Integer pin, String pinType) {
return new AttributeNameValuePin<T>(name, value, pin, pinType);
}
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> instance(String name, Class<T> type, Integer pin, String pinType) {
return new AttributeNameValuePin<T>(name, type, pin, pinType);
}
/**
* Use this to create a AttributeNameValue where the type of value is determined dynamically at runtime.
* @param <T>
* @param name
* @param type
* @param value
* @param pin
* @param pinType
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> instance(String name, Class<T> type, Comparable<? super T> value, Integer pin, String pinType) {
return new AttributeNameValuePin<T>(name, type, (T) value, pin, pinType);
}
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> instance(String name, Class<T> type, Comparable<? super T> value, Integer pin, String pinType, Attributes subAttrs) {
return new AttributeNameValuePin<T>(name, type, (T) value, pin, pinType, subAttrs);
}
/**
* Constructor that takes a DataObject as input. The DataObject
* must have <ATTRIBUTE_NAME_VALUE_PIN> as its top-level tag
*
* @param attribute DataObject containing the attribute info
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> fromDataObject(DataObject data) {
String name = data.getDataObject(ATTRIBUTE_NAME_VALUE_PIN).getValue();
String tClassName = data.getDataObject(ATTRIBUTE_TYPE).getValue();
try {
return fromDataObject(data, name, (Class<T>) Class.forName(tClassName));
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
protected static <T extends Comparable<? super T>> AttributeNameValuePin<T> fromDataObject(DataObject data, String name, Class<T> type) {
try {
Attributes subAttrs = Attributes.fromDataObject(data);
// invoke .valueOf(String) method to parse value from string
String strValue = data.getDataObject(ATTRIBUTE_VALUE).getValue();
T value = null;
if (strValue != null && !strValue.equals("null")) { // e.g. because value not set
value = valueOf(type, strValue);
}
String strPin = data.getDataObject(ATTRIBUTE_PIN).getValue();
if (strPin == null || strPin.equals("null")) { // e.g. because pin not set
return null;
}
Integer pin = Integer.valueOf(strPin);
String pinType = data.getDataObject(ATTRIBUTE_PIN_TYPE).getValue();
return AttributeNameValuePin.instance(name, type, value, pin, pinType, subAttrs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Converts this object to a DataObject.
*
* @return AttributeNameValuePin object converted to an <ATTRIBUTE_NAME_VALUE_PIN> DataObject
*/
@Override
public DataObject toDataObject() {
DataObject dobj = super.toDataObject();
// change name value pin for data object
dobj.setName(ATTRIBUTE_NAME_VALUE_PIN);
/*
* Extend data object from Attribute
*/
DataObjects children = dobj.getChildren();
children.add(new DataObject(ATTRIBUTE_PIN, String.valueOf(pin)));
children.add(new DataObject(ATTRIBUTE_PIN_TYPE, pinType));
return dobj;
}
/**
* Copy value from source attribute if their types match.
* @param source
* @return true if the copy was successful.
*/
@SuppressWarnings("unchecked")
public boolean copyValue(AttributeNameValuePin<?> source) {
if (source.getType().equals(type)) {
setValue((T)source.getValue());
return true;
}
else {
return false;
}
}
/**
* A printable version of this class.
*
* @return String version of this class
*/
public String toString() {
return super.toString() +
",pin=" + getPin() +
",pinType=" + getPinType();
}
public int getPin() {
return pin;
}
public String getPinType() {
return pinType;
}
@Override
public AttributeNameValuePin<T> clone() {
return new AttributeNameValuePin<T>(name, type, value, pin, pinType, subAttributes);
}
@Override
public AttributeNameValuePin<T> cloneWithNewName(String name) {
return new AttributeNameValuePin<T>(name, type, value, pin, pinType, subAttributes);
}
public AttributeNameValuePin<T> cloneWithNewValue(Object value) {
AttributeNameValuePin<T> att = new AttributeNameValuePin<T>(name, type, null, pin, pinType, subAttributes);
att.setValue(value);
return att;
}
/**
* Convert to value codex representation that is used by the Discoverer component model, for querying.
* Format: name+type+value+pin+pinType, where '+' would be the URL encoded form of space ' '.
* @see #fromValueCodex(String)
* @see AbstractElement#fromDataObject(DataObject)
* @return
*/
@Override
public String toValueCodex() {
return super.toValueCodex() + Discoverer.FIELD_SEPARATOR + pin + Discoverer.FIELD_SEPARATOR + pinType;
}
/**
* Create a AttributeNameValue (shallow with no sub-attributes) from the value codex representation
* that is used by the Discoverer component model, for querying.
* Format: name+type+value, where '+' would be the URL encoded form of space ' '.
* @param valueCodex
* @return
* @see #toValueCodex()
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> AttributeNameValuePin<T> fromValueCodex(String valueCodex) {
String[] args = valueCodex.split("\\+"); // "name+type+value+pin+pinType" -> {name, type, value, pin, pinType}
String name = args[0];
String typeClassname = args[1];
String strValue = args[2];
String strPin = args[3];
String pinType = args[4];
try {
Class<T> type = (Class<T>) Class.forName(typeClassname);
T value = valueOf(type, strValue);
Integer pin = Integer.valueOf(strPin);
return AttributeNameValuePin.instance(name, type, value, pin, pinType);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}