/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.target;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.opengamma.id.UniqueIdentifiable;
import com.opengamma.util.ArgumentChecker;
/**
* The type of a computation target that must be resolved within the context of outer types.
*/
/* package */final class NestedComputationTargetType extends ComputationTargetType {
private static final long serialVersionUID = 1L;
private final List<ComputationTargetType> _target;
private static final ComputationTargetTypeVisitor<List<ComputationTargetType>, Boolean> s_construct = new ComputationTargetTypeVisitor<List<ComputationTargetType>, Boolean>() {
@Override
public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final List<ComputationTargetType> data) {
// Accept
return Boolean.TRUE;
}
@Override
public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final List<ComputationTargetType> data) {
// Flatten and accept the contents
for (ComputationTargetType type : types) {
if (type.accept(this, data)) {
data.add(type);
}
}
return Boolean.FALSE;
}
@Override
public Boolean visitNullComputationTargetType(final List<ComputationTargetType> data) {
// Invalid
throw new IllegalArgumentException();
}
@Override
public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final List<ComputationTargetType> data) {
// Accept
return Boolean.TRUE;
}
};
private NestedComputationTargetType(final List<ComputationTargetType> target) {
super(NestedComputationTargetType.class.getName().hashCode() * 31 + target.hashCode());
_target = target;
}
private static List<ComputationTargetType> copy(final ComputationTargetType outerType, final ComputationTargetType innerType) {
final List<ComputationTargetType> copy = new LinkedList<ComputationTargetType>();
if (outerType.accept(s_construct, copy)) {
copy.add(outerType);
}
if (innerType.accept(s_construct, copy)) {
copy.add(innerType);
}
ArgumentChecker.isTrue(copy.size() >= 2, "target");
return Collections.unmodifiableList(new ArrayList<ComputationTargetType>(copy));
}
/**
* Creates a new instance.
*
* @param outerType the type(s) of the outer context object(s), not null
* @param innerType the type(s) of the target object(s), not null
*/
public NestedComputationTargetType(final ComputationTargetType outerType, final ComputationTargetType innerType) {
this(copy(outerType, innerType));
}
protected List<ComputationTargetType> getTypes() {
return _target;
}
@Override
public boolean isCompatible(final UniqueIdentifiable target) {
final List<ComputationTargetType> types = getTypes();
final ComputationTargetType type = types.get(types.size() - 1);
return type.isCompatible(target);
}
private static final ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean> s_isCompatible = new ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean>() {
@Override
public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final NestedComputationTargetType self) {
for (ComputationTargetType type : types) {
if (self.isCompatible(type)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
@Override
public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final NestedComputationTargetType self) {
final List<ComputationTargetType> selfTypes = self.getTypes();
if (selfTypes.size() > types.size()) {
return Boolean.FALSE;
}
for (int i = 1; i <= selfTypes.size(); i++) {
if (!selfTypes.get(selfTypes.size() - i).isCompatible(types.get(types.size() - i))) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
@Override
public Boolean visitNullComputationTargetType(final NestedComputationTargetType self) {
return Boolean.FALSE;
}
@Override
public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final NestedComputationTargetType self) {
return Boolean.FALSE;
}
};
@Override
public boolean isCompatible(final ComputationTargetType type) {
return type.accept(s_isCompatible, this);
}
@Override
public boolean isCompatible(final Class<? extends UniqueIdentifiable> clazz) {
final List<ComputationTargetType> types = getTypes();
final ComputationTargetType type = types.get(types.size() - 1);
return type.isCompatible(clazz);
}
private static final ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean> s_isTargetType = new ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean>() {
@Override
public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final NestedComputationTargetType self) {
final List<ComputationTargetType> selfTypes = self.getTypes();
final ComputationTargetType selfType = selfTypes.get(selfTypes.size() - 1);
for (ComputationTargetType type : types) {
if (selfType.isTargetType(type)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
@Override
public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final NestedComputationTargetType self) {
final List<ComputationTargetType> selfTypes = self.getTypes();
if (types.size() > selfTypes.size()) {
return Boolean.FALSE;
}
for (int i = 1; i <= types.size(); i++) {
if (!selfTypes.get(selfTypes.size() - i).isTargetType(types.get(types.size() - i))) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
@Override
public Boolean visitNullComputationTargetType(final NestedComputationTargetType self) {
return Boolean.FALSE;
}
@Override
public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final NestedComputationTargetType self) {
final List<ComputationTargetType> types = self.getTypes();
return types.get(types.size() - 1).isTargetType(type);
}
};
@Override
public boolean isTargetType(final ComputationTargetType type) {
return type.accept(s_isTargetType, this);
}
@Override
public boolean isTargetType(final Class<? extends UniqueIdentifiable> type) {
final List<ComputationTargetType> types = getTypes();
return types.get(types.size() - 1).isTargetType(type);
}
@Override
public <D, T> T accept(final ComputationTargetTypeVisitor<D, T> visitor, final D data) {
return visitor.visitNestedComputationTargetTypes(getTypes(), data);
}
protected void toStringImpl(final StringBuilder sb) {
boolean sep = false;
for (ComputationTargetType type : getTypes()) {
if (sep) {
sb.append('/');
} else {
sep = true;
}
type.toStringNested(sb);
}
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
toStringImpl(sb);
return sb.toString();
}
@Override
protected void toStringNested(final StringBuilder sb) {
sb.append('(');
toStringImpl(sb);
sb.append(')');
}
protected void getNameImpl(final StringBuilder sb) {
boolean sep = false;
for (ComputationTargetType type : getTypes()) {
if (sep) {
sb.append('/');
} else {
sep = true;
}
type.getNameNested(sb);
}
}
@Override
protected void getNameNested(final StringBuilder sb) {
sb.append('(');
getNameImpl(sb);
sb.append(')');
}
@Override
public String getName() {
final StringBuilder sb = new StringBuilder();
getNameImpl(sb);
return sb.toString();
}
private static final ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean> s_equals = new ComputationTargetTypeVisitor<NestedComputationTargetType, Boolean>() {
@Override
public Boolean visitMultipleComputationTargetTypes(final Set<ComputationTargetType> types, final NestedComputationTargetType self) {
return Boolean.FALSE;
}
@Override
public Boolean visitNestedComputationTargetTypes(final List<ComputationTargetType> types, final NestedComputationTargetType self) {
return self.getTypes().equals(types);
}
@Override
public Boolean visitNullComputationTargetType(final NestedComputationTargetType self) {
return Boolean.FALSE;
}
@Override
public Boolean visitClassComputationTargetType(final Class<? extends UniqueIdentifiable> type, final NestedComputationTargetType self) {
return Boolean.FALSE;
}
};
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (o instanceof ComputationTargetType) {
return ((ComputationTargetType) o).accept(s_equals, this).booleanValue();
} else {
return false;
}
}
}