/*
* Copyright 2003-2012 JetBrains s.r.o.
*
* 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 jetbrains.mps.smodel.structure;
import jetbrains.mps.smodel.structure.ExtensionFunction.FunctionInstance;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ExtensionFunctionPoint<T, R> extends ExtensionPoint<ExtensionFunction<T, R>> {
public ExtensionFunctionPoint(String id) {
super(id);
}
@Nullable
public FunctionInstance<R> find(T arg) {
Iterable<ExtensionFunction<T, R>> objects = getObjects();
List<ExtensionFunction<T, R>> allApplicable = new ArrayList<ExtensionFunction<T, R>>();
for (ExtensionFunction<T, R> ext : objects) {
if (ext.instantiate(arg).applicable()) {
allApplicable.add(ext);
}
}
if (allApplicable.isEmpty()) {
return null;
}
for (ExtensionFunction<T, R> ext1 : allApplicable) {
Set<ExtensionFunction<T, R>> allOverridden = new HashSet<ExtensionFunction<T, R>>(ext1.getOverridden());
ExtensionFunction<T, R> notIncluded;
do {
notIncluded = null;
for (ExtensionFunction<T, R> item : allOverridden) {
if (!allOverridden.containsAll(item.getOverridden())) {
notIncluded = item;
break;
}
}
if (notIncluded != null) {
allOverridden.addAll(notIncluded.getOverridden());
}
} while (notIncluded != null);
boolean ext1OverridesAll = true;
for (ExtensionFunction<T, R> ext2 : allApplicable) {
if (ext2 != ext1 && !allOverridden.contains(ext2)) {
ext1OverridesAll = false;
break;
}
}
if (ext1OverridesAll) {
allApplicable.remove(ext1);
return ext1.instantiate(arg);
}
}
throw new IllegalStateException("Multiple applicable extensions for extension point " + toString());
}
public R apply(T arg) {
FunctionInstance<R> functionInstance = find(arg);
if (functionInstance == null) {
throw new IllegalStateException("No applicable extensions for extension point " + toString());
}
return functionInstance.apply();
}
}