package org.rr.jeborker.metadata;
import static org.rr.commons.utils.StringUtil.EMPTY;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.rr.commons.utils.ListUtils;
import org.rr.commons.utils.StringUtil;
/**
* Class for storing metadata in a key/value kind with value class support.
*/
public class MetadataProperty implements Cloneable {
protected final String name;
protected List<Object> values;
private Class<?> propertyClass = null;
private Class<?> propertyEditorClass = null;
private Class<?> propertyRendererClass = null;
private List<String> validValues = null;
protected HashMap<MetadataProperty.HINTS, Object> hints;
public static enum HINTS {
COVER_FROM_EBOOK_FILE_NAME
}
MetadataProperty(String name, List<Object> values) {
this.name = name;
this.values = values;
}
MetadataProperty(String name, Object value) {
this.name = name;
this.values = new ArrayList<>(1);
if(value instanceof String) {
value = StringUtil.trim((String)value);
}
this.values.add(value);
}
MetadataProperty(String name, Object value, Class<?> propertyClass) {
this.name = name != null ? name.intern() : null;
this.values = new ArrayList<>(1);
this.values.add(value);
this.propertyClass = propertyClass;
}
/**
* Gets the name of the property. The name is guaranteed to be interned.
*/
public String getName() {
return name;
}
/**
* Gets the code name which can be some format specific, technical information like the record types for the mobipocket format.
*/
public String getOriginCodeName() {
return EMPTY;
}
/**
* If a {@link MetadataProperty} implementation supports multiple
* values per property, a list of values is returned here. These
* values are all from the same type or empty/null.
* @return All values for this {@link MetadataProperty}
*/
public List<Object> getValues() {
return values;
}
/**
* Convenience method to get the {@link #getValues()} as String.
* @return The desired value as String.
*/
public String getValueAsString() {
final List<Object> values = getValues();
if(values.size() > 0) {
Object object = values.get(0);
return StringUtil.toString(object);
}
return EMPTY;
}
/**
* Sets the value to the desired index.
* @param idx The index of the value
*/
public void setValue(final Object value, final int idx) {
ListUtils.set(this.values, value, idx >= 0 ? idx : 0);
}
/**
* Drop all existing values and set this ones from the given List.
* @param newValues The new values for this {@link MetadataProperty} instance.
*/
public void setValues(final List<Object> newValues) {
if(this.values != null) {
this.values.clear();
this.values.addAll(newValues);
} else {
this.values = new ArrayList<>(newValues);
}
}
public Class<?> getPropertyClass() {
if(propertyClass!=null) {
return propertyClass;
}
return String.class;
}
public void setPropertyClass(Class<?> propertyClass) {
this.propertyClass = propertyClass;
}
public String toString() {
return new ToStringBuilder(this).append("name", name).append("value", getValueAsString()).toString();
}
/**
* Tells if the property should be editable or no.
* @return <code>true</code> if the property is editable or <code>false</code> if not.
*/
public boolean isEditable() {
return true;
}
/**
* Tells if the property should be shown to the user.
* @return <code>true</code> if the property is visible or <code>false</code> if not.
*/
public boolean isVisible() {
return isCoverProperty();
}
private boolean isCoverProperty() {
return !IMetadataReader.COMMON_METADATA_TYPES.COVER.getName().equalsIgnoreCase(getName());
}
/**
* Tells if the property is deletable or not.
* @return <code>true</code> if the property is deletable or <code>false</code> if not.
*/
public boolean isDeletable() {
return true;
}
/**
* Tells if the property could inserted more than one in a document.
* @return <code>true</code> if it could not be inserted more than once and <code>false</code> otherwise.
*/
public boolean isSingle() {
return true;
}
/**
* Get a list of values which are valid for this {@link MetadataProperty}.
*/
public List<String> getValidValues() {
if(validValues == null) {
return Collections.emptyList();
}
return validValues;
}
/**
* Add values to the list of valid values.
* @param values The list of valid values.
*/
void addValidValues(List<String> values) {
if(values != null) {
if(validValues == null) {
validValues = new ArrayList<>(values);
} else {
validValues.addAll(values);
}
}
}
/**
* Creates a new {@link MetadataProperty} instance with the data of this {@link MetadataProperty}.
*/
public MetadataProperty clone() {
MetadataProperty clone = new MetadataProperty(name, new ArrayList<>(values));
clone.propertyClass = propertyClass;
clone.propertyEditorClass = propertyEditorClass;
clone.propertyRendererClass = propertyRendererClass;
clone.validValues = validValues;
clone.hints = hints;
return clone;
}
public Class<?> getPropertyEditorClass() {
return propertyEditorClass;
}
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
this.propertyEditorClass = propertyEditorClass;
}
public Class<?> getPropertyRendererClass() {
return propertyRendererClass;
}
public void setPropertyRendererClass(Class<?> propertyRendererClass) {
this.propertyRendererClass = propertyRendererClass;
}
/**
* Adds a hint to this {@link MetadataProperty} instance.
*/
public void addHint(MetadataProperty.HINTS key, Object value) {
if(hints == null) {
hints = new HashMap<MetadataProperty.HINTS, Object>();
}
hints.put(key, value);
}
/**
* Gets a previously added hint for this {@link MetadataProperty} instance.
* @return The desired hint or <code>null</code> if the desired hint is not available.
*/
public Object getHint(MetadataProperty.HINTS key) {
if(hints != null) {
return hints.get(key);
}
return null;
}
public String getAdditionalDescription() {
return EMPTY;
}
}