package de.ovgu.cide.features.source;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import cide.gast.IASTNode;
import cide.gast.ISourceFile;
import cide.gparser.ParseException;
import cide.gparser.TokenMgrError;
import cide.languages.ILanguageExtension;
import cide.languages.ILanguageParser;
import de.ovgu.cide.af.AlternativeFeatureManager;
import de.ovgu.cide.features.FeatureModelManager;
import de.ovgu.cide.features.FeatureModelNotFoundException;
import de.ovgu.cide.features.IFeatureModel;
import de.ovgu.cide.languages.LanguageExtensionManager;
import de.ovgu.cide.languages.LanguageExtensionProxy;
public class ColoredSourceFile {
protected final IFile coloredSourceFile;
protected final ILanguageExtension language;
protected WeakReference<ISourceFile> astRef = null;
protected SourceFileColorManager colorManager = null;
protected AlternativeFeatureManager altFeatureManager = null;
private final IFeatureModel featureModel;
private final IStorageProvider storageProvider;
private static final WeakHashMap<ISourceFile, ColoredSourceFile> ast2FileMap = new WeakHashMap<ISourceFile, ColoredSourceFile>();
private static final WeakHashMap<IFile, WeakReference<ColoredSourceFile>> fileCache = new WeakHashMap<IFile, WeakReference<ColoredSourceFile>>();
protected ColoredSourceFile(IFile coloredSourceFile,
IFeatureModel featureModel) {
this.coloredSourceFile = coloredSourceFile;
this.featureModel = featureModel;
this.language = findLanguageExtension(coloredSourceFile);
this.storageProvider = StorageProviderManager.getInstance()
.getStorageProvider(coloredSourceFile.getProject(),
featureModel);
// Ich denke, das brauchen wir nicht
// if (language == null)
// errorLanguageExtensionNotFound(coloredSourceFile);
}
public boolean alternativesArePossible() {
if (storageProvider == null)
return false;
return storageProvider.canHandleAlternatives();
}
/**
* returns whether this file can be colored. to be colorable the file must
* belong to a language extension so that CIDE can build an AST and has a
* pretty printer as minimum requirements.
*
* files that cannot be colored do not have a color file (or if they have it
* will be ignored)
*
* @return
*/
public boolean isColored() {
return language != null;
}
/**
* determines whether a file is colored without instanciating a
* ColoredSourceFile, thus without the need of a feature model
*
* @param coloredSourceFile
* @return
*/
public static boolean isFileColored(IFile coloredSourceFile) {
ILanguageExtension language = findLanguageExtension(coloredSourceFile);
return language != null;
}
public ISourceFile getAST() throws CoreException, ParseException {
assert isColored() : "cannot create AST because file is not colored";
if (astRef != null) {
ISourceFile r = astRef.get();
if (r != null)
return r;
}
ISourceFile r = createAST();
astRef = new WeakReference<ISourceFile>(r);
return r;
}
public ISourceFile createAST() throws CoreException, ParseException {
ISourceFile astRoot = null;
long start = System.currentTimeMillis();
ILanguageParser parser = language.getParser(coloredSourceFile
.getContents(true), coloredSourceFile.getFullPath().toOSString());
try {
astRoot = parser.getRoot();
} catch (TokenMgrError error) {
throw new ParseException(error.getMessage());
}
System.out.println("Parsed " + coloredSourceFile.getName() + " in "
+ (System.currentTimeMillis() - start) + " ms");
if (astRoot != null)
ast2FileMap.put(astRoot, this);
return astRoot;
}
public void refreshAST() {
astRef = null;
fireASTRefreshed();
}
public static ISourceFile getASTRoot(IASTNode node) {
return node.getRoot();
}
public int hashCode() {
return coloredSourceFile.hashCode();
}
public boolean equals(Object obj) {
if (!(obj instanceof ColoredSourceFile))
return false;
return coloredSourceFile
.equals(((ColoredSourceFile) obj).coloredSourceFile);
}
public SourceFileColorManager getColorManager() {
assert isColored();
if (colorManager == null) {
colorManager = new SourceFileColorManager(storageProvider, this,
DirectoryColorManager.getColoredDirectoryManagerS(
coloredSourceFile.getParent(), featureModel));
}
return colorManager;
}
public AlternativeFeatureManager getAltFeatureManager() {
if (altFeatureManager == null) {
altFeatureManager = new AlternativeFeatureManager(this);
}
return altFeatureManager;
}
private static void cache(ColoredSourceFile sourceFile) {
WeakReference<ColoredSourceFile> r = new WeakReference<ColoredSourceFile>(
sourceFile);
fileCache.put(sourceFile.coloredSourceFile, r);
}
// public static ColoredSourceFile getColoredSourceFile(IFile
// coloredSourceFile)
// throws FeatureModelNotFoundException {
// IFeatureModel fm = FeatureModelManager.getInstance().getFeatureModel(
// coloredSourceFile.getProject());
// return getColoredSourceFile(coloredSourceFile, fm);
// }
public static ColoredSourceFile getColoredSourceFile(IFile coloredSourceFile)
throws FeatureModelNotFoundException {
IFeatureModel featureModel = FeatureModelManager.getInstance()
.getFeatureModel(coloredSourceFile.getProject());
return getColoredSourceFile(coloredSourceFile, featureModel);
}
public static ColoredSourceFile getColoredSourceFile(
IFile coloredSourceFile, IFeatureModel featureModel) {
ColoredSourceFile cachedCJSF = null;
WeakReference<ColoredSourceFile> r = fileCache.get(coloredSourceFile);
if (r != null)
cachedCJSF = r.get();
if (cachedCJSF == null) {
cachedCJSF = new ColoredSourceFile(coloredSourceFile, featureModel);
cache(cachedCJSF);
}
return cachedCJSF;
}
// public IProject getProject() {
// return colorFile.getProject();
// }
public IFeatureModel getFeatureModel() {
return featureModel;
}
public boolean hasColors() {
return getColorManager().hasColors();
}
@Override
public String toString() {
return (isColored() ? "" : "(Un-)") + "Colored File "
+ coloredSourceFile.toString();
}
public String getName() {
return coloredSourceFile.getName();
}
public IFile getResource() {
return coloredSourceFile;
}
public IProject getProject() {
return getResource().getProject();
}
public ILanguageExtension getLanguageExtension() {
return language;
}
// Ich denke, das brauchen wir nicht
// private void errorLanguageExtensionNotFound(IFile input) {
// System.err.println("No language extensions registered for file "
// + input.getName());
// System.err.print("Enabled file extensions:");
// for (LanguageExtensionProxy le : LanguageExtensionManager.getInstance()
// .getEnabledLanguageExtensions())
// System.err.print(" " + le.printFileExtensions(" "));
// System.err.println();
// }
private static ILanguageExtension findLanguageExtension(IFile input) {
List<LanguageExtensionProxy> languageExtensions = LanguageExtensionManager
.getInstance().getEnabledLanguageExtensions();
String targetFileExtension = "." + input.getFileExtension();
for (LanguageExtensionProxy le : languageExtensions) {
for (String fileExtension : le.getFileExtensions())
if (fileExtension.equals(targetFileExtension))
return le;
}
return null;
}
public static IFile getResource(IASTNode node) {
ISourceFile root = node.getRoot();
ColoredSourceFile csf = ast2FileMap.get(root);
return csf == null ? null : csf.getResource();
// for (WeakReference<ColoredSourceFile> coloredSourceFileRef :
// fileCache
// .values()) {
// ColoredSourceFile coloredSourceFile = coloredSourceFileRef.get();
// if (coloredSourceFile != null) {
// WeakReference<ISourceFile> astRef = coloredSourceFile.astRef;
// if (astRef != null) {
// ISourceFile ast = astRef.get();
// if (ast == root)
// return coloredSourceFile.getResource();
// }
// }
// }
// return null;
}
private final ArrayList<IASTRefreshListener> listeners = new ArrayList<IASTRefreshListener>();
public void addASTRefreshListener(IASTRefreshListener listener) {
if (!listeners.contains(listener))
listeners.add(listener);
}
public void removeASTRefreshListener(IASTRefreshListener listener) {
listeners.add(listener);
}
protected void fireASTRefreshed() {
for (IASTRefreshListener listener : listeners) {
listener.astRefreshed(this);
}
}
}