/*
* Copyright 2003-2016 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;
import jetbrains.mps.project.AbstractModule;
import jetbrains.mps.project.DevKit;
import jetbrains.mps.project.dependency.GlobalModuleDependenciesManager;
import jetbrains.mps.project.dependency.GlobalModuleDependenciesManager.Deptype;
import jetbrains.mps.project.structure.modules.ModuleDescriptor;
import jetbrains.mps.util.CollectionUtil;
import jetbrains.mps.util.IterableUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SModuleReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
// todo: review usages and remove
public abstract class DefaultScope extends BaseScope {
private final Object LOCK = new Object();
private boolean myInitialized;
private boolean myInitializationInProgress;
private Set<SModule> myVisibleModules;
private Set<Language> myUsedLanguages;
private Set<DevKit> myUsedDevkits;
@NotNull
@Override
public Iterable<SModule> getModules() {
Set<SModule> result = new HashSet<SModule>();
synchronized (LOCK) {
initialize();
result.addAll(myVisibleModules);
result.addAll(myUsedLanguages);
result.addAll(myUsedDevkits);
}
return result;
}
@NotNull
@Override
public Iterable<SModel> getModels() {
List<SModel> result = new ArrayList<SModel>();
synchronized (LOCK) {
initialize();
for (SModule module : myVisibleModules) {
result.addAll(IterableUtil.asCollection(module.getModels()));
}
for (Language language : myUsedLanguages) {
result.addAll(language.getModels()); // todo: ?
result.addAll(language.getAccessoryModels());
}
}
return result;
}
@Override
public SModule resolve(SModuleReference reference) {
if (reference == null) {
return null;
}
SModule module = reference.resolve(MPSModuleRepository.getInstance());
if (module == null) {
return null;
}
synchronized (LOCK) {
initialize();
if (myVisibleModules.contains(module) || myUsedLanguages.contains(module) || myUsedDevkits.contains(module)) {
return module;
} else {
return null;
}
}
}
@Override
public org.jetbrains.mps.openapi.model.SModel resolve(org.jetbrains.mps.openapi.model.SModelReference reference) {
if (reference == null) {
return null;
}
SModel model = reference.resolve(MPSModuleRepository.getInstance());
if (model == null) {
return null;
}
synchronized (LOCK) {
initialize();
if (myVisibleModules.contains(model.getModule())) return model;
for (Language l : myUsedLanguages) {
if (l.getAccessoryModels().contains(model)) return model;
}
}
return null;
}
protected Collection<Language> getInitialUsedLanguages() {
return CollectionUtil.filter(Language.class, getInitialModules());
}
public void invalidateCaches() {
synchronized (LOCK) {
myVisibleModules = null;
myUsedLanguages = null;
myUsedDevkits = null;
myInitialized = false;
}
}
private void initialize() {
synchronized (LOCK) {
if (myInitialized) return;
if (myInitializationInProgress) return;
myInitializationInProgress = true;
try {
Set<SModule> initialModules = getInitialModules();
fillInDevkits(initialModules);
fillInLanguages();
fillInVisible(initialModules);
} finally {
myInitializationInProgress = false;
}
myInitialized = true;
}
}
private void fillInVisible(Set<SModule> initialModules) {
myVisibleModules = (Set<SModule>) new GlobalModuleDependenciesManager(initialModules).getModules(Deptype.VISIBLE);
}
private void fillInLanguages() {
myUsedLanguages = new HashSet<Language>();
myUsedLanguages.addAll(getInitialUsedLanguages());
for (DevKit dk : myUsedDevkits) {
myUsedLanguages.addAll(dk.getAllExportedLanguages());
}
for (Language l : new ArrayList<Language>(myUsedLanguages)) {
myUsedLanguages.addAll(l.getAllExtendedLanguages());
}
}
private void fillInDevkits(Set<SModule> initialModules) {
myUsedDevkits = new HashSet<DevKit>();
for (SModule m : initialModules) {
if (m instanceof DevKit) {
DevKit dk = (DevKit) m;
myUsedDevkits.add(dk);
myUsedDevkits.addAll(dk.getAllExtendedDevkits());
}
ModuleDescriptor moduleDescriptor = ((AbstractModule) m).getModuleDescriptor();
if (moduleDescriptor != null && moduleDescriptor.getUsedDevkits() != null) {
for (SModuleReference ref : moduleDescriptor.getUsedDevkits()) {
DevKit dk = ModuleRepositoryFacade.getInstance().getModule(ref, DevKit.class);
if (dk == null) continue;
myUsedDevkits.add(dk);
myUsedDevkits.addAll(dk.getAllExtendedDevkits());
}
}
}
}
protected abstract Set<SModule> getInitialModules();
}