package org.strategoxt.imp.runtime.dynamicloading;

import static org.strategoxt.imp.runtime.dynamicloading.TermReader.*;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.imp.language.ILanguageService;
import org.eclipse.imp.language.Language;
import org.eclipse.imp.parser.IParseController;
import org.eclipse.imp.services.ILanguageSyntaxProperties;
import org.eclipse.imp.services.IReferenceResolver;
import org.eclipse.imp.services.ITokenColorer;
import org.spoofax.interpreter.terms.IStrategoAppl;
import org.strategoxt.imp.runtime.parser.SGLRParseController;

/**
 * @author Lennart Kats <lennart add lclnet.nl>
 */
public class DynamicServiceFactory {
	private final Descriptor descriptor;
	
	private final IStrategoAppl descriptorFile;
	
	private Language language;
	
	private final Map<Class, Object> services = new HashMap<Class, Object>();
	
	public DynamicServiceFactory(Descriptor descriptor) {
		this.descriptor = descriptor;
		descriptorFile = descriptor.getDocument();
	}
	
	// LOADING SERVICES
	
	public<T extends ILanguageService> T getService(Class<T> type) throws BadDescriptorException {
		Object result = services.get(type);
		if (result != null) return type.cast(result);
		
		if (IParseController.class.isAssignableFrom(type)) {
			ILanguageSyntaxProperties syntaxProperties = getService(ILanguageSyntaxProperties.class);
			result = new SGLRParseController(getLanguage(), syntaxProperties, getStartSymbol());

		} else if (ITokenColorer.class.isAssignableFrom(type)) {
			result = TokenColorerFactory.create(descriptorFile);
		
		} else if (IReferenceResolver.class.isAssignableFrom(type)) {
			result = ReferenceResolverFactory.create(descriptor, descriptorFile);
		
		} else if (ILanguageSyntaxProperties.class.isAssignableFrom(type)) {
			result = SyntaxPropertiesFactory.create(descriptorFile);
		
		} else {
			throw new IllegalArgumentException(type.getSimpleName() + " is not a supported editor service type");
		}
		
		services.put(type, result);
		return type.cast(result);
	}
	
	// PUBLIC PROPERTIES
	
	/**
	 * Gets the language for this descriptor, but does not register it.
	 */
	public Language getLanguage() throws BadDescriptorException {
		if (language == null)
			language = new Language(
				getProperty("LanguageName"),
				getProperty("LanguageId", getProperty("LanguageName")), // natureId
				getProperty("Description", ""),
				Descriptor.ROOT_LANGUAGE,
				getProperty("URL", ""),
				getProperty("Extensions"),
				getProperty("Aliases", ""),
				null);
		return language;
	}
	
	public String getStartSymbol() {
		return getProperty("StartSymbol", null);
	}
	
	public InputStream openTableStream() throws BadDescriptorException {
		String file = getProperty("Table", getProperty("Name"));
		if (!file.endsWith(".tbl")) file += ".tbl";
		return openAttachment(file);
	}
	
	public InputStream openProviderStream() throws BadDescriptorException {
		String file = getProperty("ReferenceProvider");
		if (!file.endsWith(".ctree")) file += ".ctree";
		return openAttachment(file);
	}

	private InputStream openAttachment(String path) throws BadDescriptorException {
		try {
			return new FileInputStream(path);
		} catch (FileNotFoundException e) {
			throw new BadDescriptorException(e);
		}
	}
	
	// INTERPRETING
	
	private String getProperty(String name) throws BadDescriptorException {
		String result = getProperty(name, null);
		if (result == null) throw new BadDescriptorException("Property " + name + " not specified");		
		return result;
	}
	
	private String getProperty(String name, String defaultValue) {
		IStrategoAppl result = findTerm(descriptorFile, name);
		if (result == null) return defaultValue;

		if (termAt(result, 0) instanceof IStrategoAppl &&
				cons((IStrategoAppl) termAt(result, 0)).equals("Values")) {
			return concatTermStrings(termAt(result, 0));
		} else {
			return termContents(result);
		}
	}
}

@@ -49,177 +49,8 @@
 g;%0A%0A
-import static org.strategoxt.imp.runtime.dynamicloading.TermReader.*;%0A%0Aimport java.io.FileInputStream;%0Aimport java.io.FileNotFoundException;%0Aimport java.io.InputStream;%0A
 impo
@@ -71,16 +71,16 @@
 ashMap;%0A
+
 import j
@@ -148,50 +148,8 @@
 ce;%0A
-import org.eclipse.imp.language.Language;%0A
 impo
@@ -649,38 +649,8 @@
 ;%0A%09%0A
-%09private Language language;%0A%09%0A
 %09pri
@@ -1251,16 +1251,27 @@
 troller(
+descriptor.
 getLangu
@@ -1295,16 +1295,27 @@
 erties, 
+descriptor.
 getStart
@@ -1871,16 +1871,16 @@
 esult);%0A
+
 %09%09return
@@ -1906,1870 +1906,6 @@
 %0A%09%7D%0A
-%09%0A%09// PUBLIC PROPERTIES%0A%09%0A%09/**%0A%09 * Gets the language for this descriptor, but does not register it.%0A%09 */%0A%09public Language getLanguage() throws BadDescriptorException %7B%0A%09%09if (language == null)%0A%09%09%09language = new Language(%0A%09%09%09%09getProperty(%22LanguageName%22),%0A%09%09%09%09getProperty(%22LanguageId%22, getProperty(%22LanguageName%22)), // natureId%0A%09%09%09%09getProperty(%22Description%22, %22%22),%0A%09%09%09%09Descriptor.ROOT_LANGUAGE,%0A%09%09%09%09getProperty(%22URL%22, %22%22),%0A%09%09%09%09getProperty(%22Extensions%22),%0A%09%09%09%09getProperty(%22Aliases%22, %22%22),%0A%09%09%09%09null);%0A%09%09return language;%0A%09%7D%0A%09%0A%09public String getStartSymbol() %7B%0A%09%09return getProperty(%22StartSymbol%22, null);%0A%09%7D%0A%09%0A%09public InputStream openTableStream() throws BadDescriptorException %7B%0A%09%09String file = getProperty(%22Table%22, getProperty(%22Name%22));%0A%09%09if (!file.endsWith(%22.tbl%22)) file += %22.tbl%22;%0A%09%09return openAttachment(file);%0A%09%7D%0A%09%0A%09public InputStream openProviderStream() throws BadDescriptorException %7B%0A%09%09String file = getProperty(%22ReferenceProvider%22);%0A%09%09if (!file.endsWith(%22.ctree%22)) file += %22.ctree%22;%0A%09%09return openAttachment(file);%0A%09%7D%0A%0A%09private InputStream openAttachment(String path) throws BadDescriptorException %7B%0A%09%09try %7B%0A%09%09%09return new FileInputStream(path);%0A%09%09%7D catch (FileNotFoundException e) %7B%0A%09%09%09throw new BadDescriptorException(e);%0A%09%09%7D%0A%09%7D%0A%09%0A%09// INTERPRETING%0A%09%0A%09private String getProperty(String name) throws BadDescriptorException %7B%0A%09%09String result = getProperty(name, null);%0A%09%09if (result == null) throw new BadDescriptorException(%22Property %22 + name + %22 not specified%22);%09%09%0A%09%09return result;%0A%09%7D%0A%09%0A%09private String getProperty(String name, String defaultValue) %7B%0A%09%09IStrategoAppl result = findTerm(descriptorFile, name);%0A%09%09if (result == null) return defaultValue;%0A%0A%09%09if (termAt(result, 0) instanceof IStrategoAppl &&%0A%09%09%09%09cons((IStrategoAppl) termAt(result, 0)).equals(%22Values%22)) %7B%0A%09%09%09return concatTermStrings(termAt(result, 0));%0A%09%09%7D else %7B%0A%09%09%09return termContents(result);%0A%09%09%7D%0A%09%7D%0A
 %7D%0A

Removed some code duplication.