/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package photoSpreadObjects;
import inputOutput.XMLProcessor;
import java.awt.Component;
import java.io.BufferedWriter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import photoSpread.PhotoSpreadException;
import photoSpread.PhotoSpreadException.BadUUIDStringError;
import photoSpread.PhotoSpreadException.CannotLoadImage;
import photoSpreadParser.photoSpreadExpression.PhotoSpreadComputable;
import photoSpreadParser.photoSpreadExpression.photoSpreadFunctions.FunctionResultable;
import photoSpreadTable.PhotoSpreadCell;
import photoSpreadUtilities.Const;
import photoSpreadUtilities.Misc;
import photoSpreadUtilities.PhotoSpreadHelpers;
import photoSpreadUtilities.Misc.Pair;
import photoSpreadUtilities.UUID;
/**
*
* @author skandel
*/
public abstract class PhotoSpreadObject implements Comparable<PhotoSpreadObject>,
FunctionResultable, PhotoSpreadComputable {
private UUID _objectId;
private TreeMap<String, String> _metadata;
protected PhotoSpreadCell _cell;
public static String FILEPATH_ARG = "_filePath";
/****************************************************
* Constructor(s)
*****************************************************/
/**
* returns an instance of a photo spread object, given
* the type of the object and the arguments to that type's
* constructor
* @param cell The cell that contains the object
* @param objectType the type of object
* @param args An array of arguments to pass to object constructor.
* @return the object created
*/
/**
* Instantiate a PhotoSpread object from information
* in an XML file. Called from unmarshallObject(Node, PhotoSpreadCell).
* @param cell Cell where the object will reside
* @param objectType PhotoSpread class to instantiate
* @param args Arguments to the instance construction
* @return
*/
static public PhotoSpreadObject getInstance(PhotoSpreadCell cell, String objectType, ArrayList<String> args)
throws BadUUIDStringError {
PhotoSpreadObject obj = null;
Constructor<?> cstr = null;
try{
Class<?> cl = Class.forName(objectType);
switch (args.size()) {
// Create constructor with 2 arguments:
// a cell, and a string, which is the new object's
// file path:
case 1:
cstr = cl.getConstructor(PhotoSpreadCell.class, String.class);
obj = (PhotoSpreadObject) cstr.newInstance(cell, args.get(0));
break;
// Create constructor with 3 arguments:
case 2:
// A cell, the string version of a UUID from which a UUID object
// can be created, and the filename of the object:
cstr = cl.getConstructor(PhotoSpreadCell.class, String.class, String.class);
obj = (PhotoSpreadObject) cstr.newInstance(cell, args.get(0), args.get(1));
break;
default:
throw new PhotoSpreadException.BadObjectInstantiationFromString(
"Object instantiation for constructor with " +
args.size() +
" arguments: " +
args
);
}
return obj;
}
catch(java.lang.NoSuchMethodException e){
Misc.showErrorMsgAndStackTrace(e, "");
//System.out.println(e.getMessage());
//e.printStackTrace();
}
catch(java.lang.IllegalAccessException e){
Misc.showErrorMsgAndStackTrace(e, "");
//System.out.println(e.getMessage());
//e.printStackTrace();
}
catch(java.lang.IllegalArgumentException e){
Misc.showErrorMsgAndStackTrace(e, "");
//System.out.println(e.getMessage());
//e.printStackTrace();
}
catch(java.lang.InstantiationException e){
Misc.showErrorMsgAndStackTrace(e, "");
//System.out.println(e.getMessage());
//e.printStackTrace();
}
catch(java.lang.Exception e){
Misc.showErrorMsgAndStackTrace(e, "");
//System.out.println(e.getMessage());
//e.printStackTrace();
}
return null;
}
public PhotoSpreadObject(PhotoSpreadCell _cell, UUID _objectId){
this._objectId = _objectId;
_metadata = new TreeMap<String, String>();
this._cell = _cell;
}
public PhotoSpreadObject(PhotoSpreadCell _cell, UUID _objectId, String fileName){
// We throw the filename away (future use, maybe):
this(_cell, _objectId);
}
/* public PhotoSpreadObject(PhotoSpreadCell _cell){
this(_cell, new UUID());
}
*/
/****************************************************
* Methods
*****************************************************/
public int compareTo (PhotoSpreadObject o) {
return _objectId.compareTo(o.getObjectID());
}
/**
* Associative search ('equal by contents').
* Given a piece of 'content,' return true if
* this object contains the content, false otherwise.
* Subclasses of PhotoSpreadObject are expected to
* provide appropriate implementations for this method.
* For example:
* o PhotoSpreadStringObject: true if the string object
* wraps a string that is '.equals(<the given content>)
* o PhotoSpreadDoubleObject: true if the object's
* wrapped number is '==' to the given content.
* o PhotoSpreadFileObject: true if filenames are .equals.
* o PhotoSpreadTableObject: true if uuid's are .equals.
* This class implements one version that returns true if
* a given attribute/value pair is present in this object's
* metadata.
*
* @param obj The piece of content against which to compare.
* @return True if this object contains the given content. Else false.
*/
public abstract <T extends Object> boolean contentEquals(T obj);
/**
* Given an attribute/value pair, return true if this object's
* metadata contains that attribute/value pair (using equals()).
*
* @param metaData A Pair whose first() is an attribute (String),
* and whose second() is a value (String). If the attribute part
* is null, this method returns true if any of the metadata entries
* strore the given value.
*
* @return True if given pair is represented in this object's metadata,
* else False.
*/
public boolean contentEquals(Pair<String, String> metaData) {
String attr = metaData.first();
String value = metaData.second();
// If attr==null: check for presence of value in
// *any* of the values:
if (attr == null)
return _metadata.containsValue(value);
if (!_metadata.containsKey(attr))
return false;
String storedValue = _metadata.get(attr);
return storedValue.equals(value);
}
public PhotoSpreadCell getCell() {
return _cell;
}
public void setCell(PhotoSpreadCell _cell) {
this._cell = _cell;
}
/**
* Returns a primitive object appropriate for the
* type. Examples: PhotoSpreadDoubleObject-->Double.
* PhotoSpreadFileObject->File (i.e. an instance of
* the Java File type)
* @return Primitive object of appropriate type.
*/
public abstract Object valueOf();
/**
* Return a Double if one can successfully cast.
* Else throw a ClassCastException.
*
* @return a Double number that corresponds to the object.
*/
public abstract Double toDouble() throws ClassCastException;
/**
* Return a String if one can successfully cast.
* Else throw a ClassCastException.
*
* @return a String that corresponds to the object.
*/
public abstract String toString() throws ClassCastException;
public UUID getObjectID() {
return _objectId;
}
public void setObjectID(UUID theID) {
_objectId = theID;
}
/**
* Sets the metadata of an object
* @param attr the attribute being set
* @param newValue the value being set
*/
public void setMetaData(String attr, String newValue){
// In case this cell is indexed by metadata,
// update that index by supplying the current and
// new value:
if (_cell.hasMetadataIndexer())
_cell.invalidateMetadataIndexer(
this,
attr,
getMetaData(attr),
newValue);
_metadata.put(attr, newValue);
}
/**
* Returns the value for a given attribute of object metadata
* @param attr the attribute
* @return the value for attr
*/
public String getMetaData(String attr){
// The attribute might not be defined,
// returning null for get(attr). We
// want that null to be a string so that
// formulas can compare against
String res = _metadata.get(attr);
return (res == null) ? Const.NULL_VALUE_STRING : res;
}
/**
* Returns the attributes for all metadata in the object
* @return A set of all attributes
*/
public Set<String> getMetaDataKeySet(){
return _metadata.keySet();
}
/**
* Returns the metadata in the object
* @return An arraylist of metadata
*/
public ArrayList<ArrayList<String>> getMetaDataSet(){
Iterator<Entry<String, String>> it = _metadata.entrySet().iterator();
ArrayList<ArrayList<String>> dataSet = new ArrayList<ArrayList<String>>();
while(it.hasNext()){
Entry<String, String> entry = it.next();
ArrayList<String> set = new ArrayList<String>();
set.add(entry.getKey());
set.add(entry.getValue());
dataSet.add(set);
}
return dataSet;
}
public void setMetaData(ArrayList<ArrayList<String>> data){
clearMetadata();
Iterator<ArrayList<String>> it = data.iterator();
while(it.hasNext()){
ArrayList<String> set = it.next();
if(!set.get(0).equals("")){
setMetaData(set.get(0), set.get(1));
}
}
}
abstract public <T extends PhotoSpreadObject> T copyObject ();
private void clearMetadata(){
_metadata.clear();
_cell.clearMetadataIndexer();
}
/**
* returns the component representing the object
* @param height height of component
* @param width width of component
* @return the component representing object
*/
abstract public Component getObjectComponent(int height, int width)
throws CannotLoadImage;
/**
* returns the component representing the object
* @param height height of component
* @param width width of component
* @return the component representing object
* @throws CannotLoadImage
*/
public Component getWorkspaceComponent(int height, int width) throws CannotLoadImage{
return getObjectComponent(height, width);
}
/**
* returns string of object's xml representation
* @return String of xml representation
*/
public String toXML(){
StringBuffer xml = new StringBuffer();
xml.append(objectToXMLTag(this.getClass().getName()));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_CONSTRUCTOR_ARGUMENTS_ELEMENT, true));
xml.append(constructorArgsToXML());
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_CONSTRUCTOR_ARGUMENTS_ELEMENT, false));
xml.append(metaDataToXML());
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_ELEMENT, false));
return xml.toString();
}
/**
* writes the object to xml
* @param out the stream to write to
*/
public void toXML(BufferedWriter out){
try{
out.write(objectToXMLTag(this.getClass().getName()));
out.write(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_CONSTRUCTOR_ARGUMENTS_ELEMENT, true));
out.write(constructorArgsToXML());
out.write(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_CONSTRUCTOR_ARGUMENTS_ELEMENT, false));
out.write(metaDataToXML());
out.write(PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_ELEMENT, false));
}
catch(java.io.IOException e){
System.out.println("to xml failed caught IOException");
}
}
protected String metaDataToXML(){
StringBuffer xml = new StringBuffer();
Iterator<Entry<String, String>> it = _metadata.entrySet().iterator();
while(it.hasNext()){
Entry<String, String> entry = it.next();
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAGS_ELEMENT, true));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAG_ELEMENT, true));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAG_ATTRIBUTE_ELEMENT, entry.getKey()));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAG_VALUE_ELEMENT, entry.getValue()));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAG_ELEMENT, false));
xml.append(PhotoSpreadHelpers.getXMLElement(XMLProcessor.TAGS_ELEMENT, false));
}
return xml.toString();
}
protected String objectToXMLTag(String objectType){
return PhotoSpreadHelpers.getXMLElement(XMLProcessor.OBJECT_ELEMENT + " " + XMLProcessor.OBJECT_TYPE_ELEMENT + "=" + "\"" + objectType + "\"", true);
}
abstract public String constructorArgsToXML();
}