/*
* 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.newTypesystem.rules;
import jetbrains.mps.languageScope.LanguageScope;
import jetbrains.mps.smodel.NodeReadAccessCasterInEditor;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.util.Computable;
import jetbrains.mps.util.Pair;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* User: fyodor
* Date: 8/28/12
*/
public abstract class SingleTermRules<K> {
private ConcurrentHashMap<Object, Set<K>> myCachedRules = new ConcurrentHashMap<Object, Set<K>>();
public Set<K> lookupRules(SNode term) {
final LanguageScope langScope = LanguageScope.getCurrent();
final SAbstractConcept concept = term.getConcept();
final Object compoundKey = new Pair<Object, SAbstractConcept>(langScope, concept);
Set<K> cachedRules = myCachedRules.get(compoundKey);
if (cachedRules != null) {
return cachedRules;
}
return NodeReadAccessCasterInEditor.runReadTransparentAction(new Computable<Set<K>>() {
@Override
public Set<K> compute() {
Set<K> computedRules = computeRules(concept, langScope);
myCachedRules.put(compoundKey, computedRules);
return computedRules;
}
});
}
public void purgeCache() {
myCachedRules.clear();
}
private Set<K> computeRules(SAbstractConcept concept, LanguageScope langScope) {
LinkedHashSet<K> result = new LinkedHashSet<K>();
LinkedList<SAbstractConcept> queue = new LinkedList<SAbstractConcept>();
queue.add(concept);
while (!queue.isEmpty()) {
SAbstractConcept nextConceptFQName = queue.remove();
boolean overriding = false;
for (K applicableRule : allForConcept(nextConceptFQName, langScope)) {
overriding |= isOverriding(applicableRule);
result.add(applicableRule);
}
if (!overriding) {
queue.addAll(getParents(nextConceptFQName));
}
}
return Collections.unmodifiableSet(result);
}
abstract protected List<SAbstractConcept> getParents(SAbstractConcept nextConcept);
abstract protected Iterable<K> allForConcept(SAbstractConcept concept, LanguageScope scope);
abstract protected boolean isOverriding(K rule);
}