package edu.umd.rhsmith.diads.meater.core.config.components.media;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.configuration.HierarchicalConfiguration;
import edu.umd.rhsmith.diads.meater.core.app.MEaterConfigurationException;
import edu.umd.rhsmith.diads.meater.core.app.components.media.MediaClassNotFoundException;
import edu.umd.rhsmith.diads.meater.core.app.components.media.MediaPath;
import edu.umd.rhsmith.diads.meater.core.app.components.media.MediaPathInitializer;
import edu.umd.rhsmith.diads.meater.core.config.components.ComponentConfig;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathDescriptionOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathProcessorAddOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathProcessorListOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathProcessorRemoveOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathRejectableOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathSetMediaOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathSourceAddOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathSourceListOperation;
import edu.umd.rhsmith.diads.meater.core.config.setup.ops.media.path.PathSourceRemoveOperation;
public final class MediaPathConfig extends ComponentConfig {
public static final String CKEY_SOURCE = "source";
public static final String CKEY_PROCESSOR = "processor";
public static final String CKEY_MEDIA_CLASS = "mediaClass";
public static final String CKEY_REJECTABLE = "rejectable";
public static final String CKEY_DESCR = "description";
private Class<?> mediaClass;
private final Collection<String> sources;
private final List<String> processors;
public boolean rejectable;
private String description;
MediaPathConfig() {
super();
this.sources = new HashSet<String>();
this.processors = new ArrayList<String>();
this.setMediaClass(null);
this.setDescription("");
// manipulate processors
this.registerSetupConsoleOperation(new PathProcessorAddOperation(this));
this.registerSetupConsoleOperation(new PathProcessorRemoveOperation(
this));
this.registerSetupConsoleOperation(new PathProcessorListOperation(this));
// manipulate sources
this.registerSetupConsoleOperation(new PathSourceAddOperation(this));
this.registerSetupConsoleOperation(new PathSourceRemoveOperation(this));
this.registerSetupConsoleOperation(new PathSourceListOperation(this));
// media types
this.setCreationSetupConsoleOperation(new PathSetMediaOperation(this));
this.registerSetupConsoleOperation(this
.getCreationSetupConsoleOperation());
// misc
this.registerSetupConsoleOperation(new PathRejectableOperation(this));
this.registerSetupConsoleOperation(new PathDescriptionOperation(this));
}
@Override
public MediaPath<?> instantiateComponent()
throws MEaterConfigurationException {
// use these intermediate steps to maintain type safety - parameter M is
// inferred from generic wildcard of current media class
if (this.mediaClass != null) {
return this.createTypeSafe(this.mediaClass);
} else {
throw new MEaterConfigurationException(String.format(
MSG_ERR_NO_CLASS, this.getInstanceName()));
}
}
private <M> MediaPath<M> createTypeSafe(Class<M> mediaClass)
throws MEaterConfigurationException {
return new MediaPath<M>(this.new Initializer<M>(mediaClass));
}
private class Initializer<M> implements MediaPathInitializer<M> {
private Class<M> mediaClass;
public Initializer(Class<M> mediaClass) {
this.mediaClass = mediaClass;
}
@Override
public String getInstanceName() {
return MediaPathConfig.this.getInstanceName();
}
@Override
public Class<M> getMediaClass() {
return mediaClass;
}
@Override
public Collection<String> getSourceNames() {
return MediaPathConfig.this.getSources();
}
@Override
public Collection<String> getProcessorNames() {
return MediaPathConfig.this.getProcessors();
}
@Override
public boolean isRejectable() {
return MediaPathConfig.this.rejectable;
}
}
/*
* --------------------------------
* General getters & setters
* --------------------------------
*/
public Class<?> getMediaClass() {
return mediaClass;
}
public void setMediaClass(Class<?> mediaClass) {
this.mediaClass = mediaClass;
if (mediaClass != null) {
this.registerMediaProcessorName("", mediaClass);
} else {
this.unregisterMediaProcessorName("");
}
}
public String getDescription() {
return description;
}
public void setDescription(String description) throws NullPointerException {
if (description == null) {
throw new NullPointerException();
}
this.description = description;
}
public boolean isRejectable() {
return rejectable;
}
public void setRejectable(boolean rejectable) {
this.rejectable = rejectable;
}
/*
* --------------------------------
* Handlers & sources
* --------------------------------
*/
public boolean addProcessor(String name) {
return this.processors.add(name);
}
public void addProcessor(int index, String name) {
this.processors.add(index, name);
}
public boolean removeProcessor(String name) {
return this.processors.remove(name);
}
public List<String> getProcessors() {
return new ArrayList<String>(this.processors);
}
public int getNumProcessors() {
return this.processors.size();
}
public boolean addSource(String name) {
return this.sources.add(name);
}
public boolean removeSource(String name) {
return this.sources.remove(name);
}
public List<String> getSources() {
return new ArrayList<String>(this.sources);
}
public int getNumSources() {
return this.sources.size();
}
/*
* --------------------------------
* UI
* --------------------------------
*/
@Override
public String getUiName() {
if (this.mediaClass != null) {
return String.format(MSG_OPERATES_ON_FMT, super.getUiName(),
this.mediaClass.getName());
} else {
return String.format(MSG_OPERATES_ON_NONE_FMT, super.getUiName());
}
}
@Override
public String getUiDescription() {
return this.getDescription();
}
/*
* --------------------------------
* Config operations
* --------------------------------
*/
@Override
public void resetInternalConfiguration() {
this.sources.clear();
this.processors.clear();
this.rejectable = false;
this.description = "";
}
@Override
protected void loadInternalConfigurationFrom(
HierarchicalConfiguration config)
throws MEaterConfigurationException {
super.loadInternalConfigurationFrom(config);
this.description = config.getString(CKEY_DESCR, this.description);
this.rejectable = config.getBoolean(CKEY_REJECTABLE, this.rejectable);
for (String s : config.getStringArray(CKEY_SOURCE)) {
this.sources.add(s);
}
for (String s : config.getStringArray(CKEY_PROCESSOR)) {
this.processors.add(s);
}
loadMediaClass(config);
}
@Override
protected void saveInternalConfigurationTo(HierarchicalConfiguration config)
throws MEaterConfigurationException {
super.saveInternalConfigurationTo(config);
config.setProperty(CKEY_REJECTABLE, this.rejectable);
config.setProperty(CKEY_DESCR, this.description);
for (String s : this.sources) {
config.addProperty(CKEY_SOURCE, s);
}
for (String s : this.processors) {
config.addProperty(CKEY_PROCESSOR, s);
}
saveMediaClass(config);
}
private void loadMediaClass(HierarchicalConfiguration config)
throws MediaClassNotFoundException {
String className = config.getString(CKEY_MEDIA_CLASS);
if (className != null) {
try {
Class<?> mediaClass = Class.forName(className);
this.setMediaClass(mediaClass);
} catch (ClassNotFoundException e) {
throw new MediaClassNotFoundException(className);
}
}
}
private void saveMediaClass(HierarchicalConfiguration config) {
if (this.mediaClass != null) {
config.addProperty(CKEY_MEDIA_CLASS, this.mediaClass
.getCanonicalName());
}
}
/*
* --------------------------------
* Config type registration
* --------------------------------
*/
public static final String TNAME = "MediaPath";
public static final String TDESC = "Define a mapping of media source inputs to media processors";
/*
* --------------------------------
* Messages
* --------------------------------
*/
private static final String MSG_ERR_NO_CLASS = "Media path %s has no assigned media class, cannot instantiate.";
private static final String MSG_OPERATES_ON_FMT = "%s (operates on %s)";
private static final String MSG_OPERATES_ON_NONE_FMT = "%s (no media class set)";
}