package org.jetbrains.plugins.ruby.motion.facet;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.facet.FacetType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiTreeChangeAdapter;
import com.intellij.psi.PsiTreeChangeEvent;
import com.intellij.util.ActionRunner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.ruby.gem.GemModificationUtil;
import org.jetbrains.plugins.ruby.motion.RubyMotionUtil;
import org.jetbrains.plugins.ruby.motion.paramdefs.RubyMotionParamdefsProvider;
import org.jetbrains.plugins.ruby.ruby.lang.psi.RFile;
import org.jetbrains.plugins.ruby.tasks.rake.RakeUtilBase;
import org.jetbrains.plugins.ruby.utils.IdeaInternalUtil;
import org.jetbrains.plugins.ruby.utils.VirtualFileUtil;
/**
* @author Dennis.Ushakov
*/
public class RubyMotionFacet extends Facet<RubyMotionFacetConfiguration> {
public RubyMotionFacet(@NotNull final FacetType facetType,
@NotNull final Module module,
@NotNull final String name,
@NotNull final RubyMotionFacetConfiguration configuration,
final Facet underlyingFacet) {
super(facetType, module, name, configuration, underlyingFacet);
}
@Override
public void initFacet() {
PsiManager.getInstance(getModule().getProject()).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
@Override
public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
resetCachesIfNeeded(event);
}
@Override
public void childAdded(@NotNull PsiTreeChangeEvent event) {
resetCachesIfNeeded(event);
}
@Override
public void childRemoved(@NotNull PsiTreeChangeEvent event) {
resetCachesIfNeeded(event);
}
@Override
public void childReplaced(@NotNull PsiTreeChangeEvent event) {
resetCachesIfNeeded(event);
}
@Override
public void childMoved(@NotNull PsiTreeChangeEvent event) {
resetCachesIfNeeded(event);
}
});
if (!ApplicationManager.getApplication().isUnitTestMode()) {
RubyMotionParamdefsProvider.ensureParamdefsLoaded();
}
}
private void resetCachesIfNeeded(final PsiTreeChangeEvent event) {
final PsiFile file = event.getFile();
if (file instanceof RFile && RakeUtilBase.RAKE_FILE.equals(file.getName())) {
RubyMotionUtil.getInstance().resetSdkAndFrameworks(getModule());
}
}
@Nullable
public static RubyMotionFacet getInstance(@NotNull final Module module) {
if (module.isDisposed()) {
return null;
}
return FacetManager.getInstance(module).getFacetByType(RubyMotionFacetType.ID);
}
public static void updateMotionLibrary(final ModifiableRootModel model) {
IdeaInternalUtil.runInsideWriteAction(new ActionRunner.InterruptibleRunnable() {
public void run() throws Exception {
boolean librarySeen = false;
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof LibraryOrderEntry) {
final String libraryName = ((LibraryOrderEntry)entry).getLibraryName();
if (RubyMotionUtil.RUBY_MOTION_LIBRARY.equals(libraryName)) {
librarySeen = true;
break;
}
}
}
if (!librarySeen) {
Library library = LibraryTablesRegistrar.getInstance().getLibraryTable().getLibraryByName(RubyMotionUtil.RUBY_MOTION_LIBRARY);
if (library == null) {
// we just create new project library
library = createLibrary();
}
if (library != null) {
final LibraryOrderEntry libraryOrderEntry = model.addLibraryEntry(library);
libraryOrderEntry.setScope(DependencyScope.PROVIDED);
}
}
}
});
}
@Nullable
private static Library createLibrary() {
final VirtualFile motion = VirtualFileUtil.findFileBy(RubyMotionUtil.getInstance().getRubyMotionPath());
if (motion == null) return null;
final LibraryTable.ModifiableModel model = GemModificationUtil.getLibraryTableModifiableModel();
final Library library = model.createLibrary(RubyMotionUtil.RUBY_MOTION_LIBRARY);
final Library.ModifiableModel libModel = library.getModifiableModel();
for (VirtualFile child : motion.getChildren()) {
if (child != null) {
libModel.addRoot(child, OrderRootType.CLASSES);
libModel.addRoot(child, OrderRootType.SOURCES);
}
}
libModel.commit();
model.commit();
return library;
}
}