package org.fandev.module;
import com.intellij.ProjectTopics;
import com.intellij.openapi.module.*;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.messages.MessageBusConnection;
import org.fandev.sdk.FanSdkType;
import org.jetbrains.annotations.NotNull;
import org.fandev.settings.FanModuleSettingsStorage;
import org.fandev.settings.SettingAttribute;
import org.fandev.module.ModuleSynchFileListener;
import org.fandev.module.pod.PodModel;
import org.fandev.module.pod.PodFileParser;
import org.fandev.utils.VirtualFileUtil;
import org.fandev.index.FanIndex;
import java.util.*;
/**
* @author Dror Bereznitsky
* @date Jan 27, 2009 7:10:11 PM
*/
public class FanModuleSettings implements ModuleComponent {
protected final Module myModule;
private FanModuleSettingsStorage myModuleSettingsStorage;
private ModuleSynchFileListener buildScriptListener;
private FanIndex fanIndex;
public static final String COMPONENT_NAME = "FanModuleSettings";
private static final Logger logger = Logger.getInstance("Settings");
public FanModuleSettings(final Module module) {
myModule = module;
myModuleSettingsStorage = FanModuleSettingsStorage.getInstance(module);
buildScriptListener = new ModuleSynchFileListener(getBuildScript(), module);
fanIndex = (FanIndex) module.getProject().getComponent(FanIndex.COMPONENT_NAME);
final MessageBusConnection conn = myModule.getMessageBus().connect();
conn.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
private Sdk lastSdk;
public void beforeRootsChange(ModuleRootEvent event) {
lastSdk = ModuleRootManager.getInstance(myModule).getSdk();
}
public void rootsChanged(ModuleRootEvent event) {
final Sdk moduleSdk = ModuleRootManager.getInstance(myModule).getSdk();
if (moduleSdk != null && !moduleSdk.equals(lastSdk)) {
if (fanIndex != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
final ModifiableRootModel modifiableRootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
final LibraryTable libraryTable = modifiableRootModel.getModuleLibraryTable();
final Library[] libraries = libraryTable.getLibraries();
for (Library lib : libraries) {
fanIndex.indexLibrary(lib);
}
}
});
}
}
}
});
}
public static FanModuleSettings getInstance(@NotNull final Module module) {
return module.getComponent(FanModuleSettings.class);
}
public VirtualFile getBuildScript() {
return getVirtualFileAttribute(SettingAttribute.BUILD_SCRIPT);
}
public String getBuildScriptPath() {
return myModuleSettingsStorage.getAttributeValue(SettingAttribute.BUILD_SCRIPT);
}
public void setBuildScript(final VirtualFile buildScript) {
setVirtualFileAttribute(SettingAttribute.BUILD_SCRIPT, buildScript);
buildScriptListener = new ModuleSynchFileListener(buildScript, myModule);
}
public Module getModule() {
return myModule;
}
private VirtualFile getVirtualFileAttribute(final SettingAttribute attribute) {
final String url = myModuleSettingsStorage.getAttributeValue(attribute);
return VirtualFileManager.getInstance().refreshAndFindFileByUrl(url);
}
private void setVirtualFileAttribute(final SettingAttribute attribute, final VirtualFile value) {
final String url = value != null ? value.getUrl() : "";
myModuleSettingsStorage.setAttributeValue(attribute, url);
}
@NotNull
public String getComponentName() {
return COMPONENT_NAME;
}
/**
* Should run in the scope of a write action
*/
public void synchModule() {
final String s = VirtualFileUtil.buildUrl(myModule.getModuleFile().getParent().getPath(), PodModel.BUILD_FAN);
final VirtualFile v = VirtualFileUtil.refreshAndFindFileByLocalPath(s);
FanModuleSettings.getInstance(myModule).setBuildScript(v);
setBuildScript(v);
final PodModel podModel = PodFileParser.parse(getBuildScript(), myModule);
if (podModel != null) {
final ModifiableRootModel modifiableRootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
final ContentEntry[] entries = modifiableRootModel.getContentEntries();
for (final ContentEntry entry : entries) {
if (entry.getFile().equals(myModule.getModuleFile().getParent())) {
final SourceFolder[] sourceFolders = entry.getSourceFolders();
for (final SourceFolder srcFolder : sourceFolders) {
entry.removeSourceFolder(srcFolder);
}
for (final Pair<String,String> srcDir : podModel.getSrcDirs()) {
final VirtualFile sourceFolder = VirtualFileManager.getInstance().refreshAndFindFileByUrl(VirtualFileUtil.buildUrl(entry.getUrl(), srcDir.getFirst()));
if (sourceFolder != null) {
entry.addSourceFolder(sourceFolder, false);
}
}
}
}
synchLibraries(podModel, modifiableRootModel);
modifiableRootModel.commit();
if (!myModule.getName().equals(podModel.getName())) {
final ModifiableModuleModel moduleModel = ModuleManager.getInstance(myModule.getProject()).getModifiableModel();
try {
moduleModel.renameModule(myModule, podModel.getName());
moduleModel.commit();
} catch (ModuleWithNameAlreadyExists moduleWithNameAlreadyExists) {
// Could not rename
logger.error("Failed to rename module " + myModule.getName() + " to " + podModel.getName());
}
}
} else {
WindowManager.getInstance().getStatusBar(myModule.getProject()).setInfo("Failed to parse build script");
}
}
private void synchLibraries(final PodModel podModel, final ModifiableRootModel modifiableRootModel) {
// Add pod dependencies as module libraries
final LibraryTable libraryTable = modifiableRootModel.getModuleLibraryTable();
final Library[] libraries = libraryTable.getLibraries();
final List<String> dependencies = podModel.getDeclaredDependencies();
final List<String> dependenciesToAdd = new LinkedList<String>(dependencies);
for (final Library library : libraries) {
final String libName = library.getName();
if (dependencies.contains(libName)) {
dependenciesToAdd.remove(libName); // only add new libraries
} else {
libraryTable.removeLibrary(library);
}
}
final Sdk moduleSdk = ModuleRootManager.getInstance(myModule).getSdk();
for (final String dependency : dependenciesToAdd) {
String podName = dependency.indexOf(' ') > 0 ? dependency.substring(0, dependency.indexOf(' ')) : dependency;
String moduleLibraryPath = VirtualFileUtil.constructLocalUrl(String.format("%s%s%s%s%s.pod", moduleSdk.getHomePath(),
VirtualFileUtil.VFS_PATH_SEPARATOR, FanSdkType.getFanLibDir(),
VirtualFileUtil.VFS_PATH_SEPARATOR, podName));
String sourceLibraryPath = VirtualFileUtil.constructLocalUrl(String.format("%s%s%s%s%s%s", moduleSdk.getHomePath(),
VirtualFileUtil.VFS_PATH_SEPARATOR, FanSdkType.getSrcDir(),
VirtualFileUtil.VFS_PATH_SEPARATOR, podName, VirtualFileUtil.VFS_PATH_SEPARATOR));
final Library library = libraryTable.createLibrary();
final Library.ModifiableModel modifiableModel = library.getModifiableModel();
modifiableModel.setName(dependency);
modifiableModel.addRoot(moduleLibraryPath, OrderRootType.CLASSES);
if (sourceLibraryPath != null) {
modifiableModel.addRoot(sourceLibraryPath, OrderRootType.SOURCES);
}
modifiableModel.commit();
if (fanIndex != null) {
fanIndex.indexLibrary(library);
}
}
}
public void projectOpened() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
synchModule();
}
});
}
public void projectClosed() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void moduleAdded() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void initComponent() {
VirtualFileManager.getInstance().addVirtualFileListener(buildScriptListener);
}
public void disposeComponent() {
VirtualFileManager.getInstance().removeVirtualFileListener(buildScriptListener);
}
}