/*******************************************************************************
* Copyright 2011
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.dkpro.lab.task;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import org.dkpro.lab.task.impl.DimensionBundle;
import org.dkpro.lab.task.impl.DiscreteDimension;
/**
* A dimension in a {@link ParameterSpace}.
*/
public abstract class Dimension<T>
implements Iterator<T>
{
private final String name;
public Dimension(String aName)
{
name = aName;
}
public String getName()
{
return name;
}
/**
* Reset dimension to before the first value. A call to {@link #next} will return the first
* value.
*/
public abstract void rewind();
/**
* Get the next value.
*
* @throws NoSuchElementException if the dimension is empty.
*/
@Override
public abstract T next();
/**
* Get the current value.
*
* @throws NoSuchElementException if the dimension is empty.
*/
public abstract T current();
/**
* Removing values from a dimension is not supported.
*
* @throws UnsupportedOperationException operation is not supported.
*/
@Override
public void remove()
{
throw new UnsupportedOperationException("No no");
}
/**
* Create a new dimension. If only one value is given an that is a subclass of {@link Enum},
* then this method forwards to {@link #create(String, Class)}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> Dimension<T> create(String aName, T... aValues)
{
if (aValues.length == 1 && (aValues[0] instanceof Class)) {
// Dispatch to enum factory method
Class<?> clazz = (Class<?>) aValues[0];
if (Enum.class.isAssignableFrom(clazz)) {
return (Dimension<T>) create(aName, (Class<Enum>) clazz);
}
}
return new DiscreteDimension<T>(aName, aValues);
}
@SafeVarargs
public static <T> Dimension<Map<String, T>> createBundle(String aName, Map<String, T>... aValues)
{
return new DimensionBundle<T>(aName, aValues);
}
public static <T> Dimension<Map<String, T>> createBundle(String aName, Object[]... aValues)
{
return new DimensionBundle<T>(aName, aValues);
}
/**
* Create a new dimension from the values of an {@link Enum}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T extends Enum<T>> Dimension<T> create(String aName, Class<T> aEnum)
{
if (!Enum.class.isAssignableFrom(aEnum)) {
// Dispatch to non-enum factory method - this is necessary because Java dispatches to
// this method when create(name, class) is called. Obviously the generic type
// restriction is ignored at runtime.
return (Dimension) create(aName, new Object[] { aEnum } );
}
try {
T[] values = (T[]) aEnum.getMethod("values").invoke(null, (Object[]) null);
return new DiscreteDimension<T>(aName, values);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Fetches the value associated with this dimension from the given configuration.
*
* @param aMap the configuration.
* @return the value for this dimension.
*/
@SuppressWarnings("unchecked")
public T get(Map<String, Object> aMap)
{
if (getName() == null) {
throw new IllegalStateException("Cannot use 'get' on anonmyous dimensions");
}
return (T) aMap.get(getName());
}
}