package org.strategoxt.imp.testing.cmd.strategies;

import static org.spoofax.interpreter.core.Tools.asJavaString;
import static org.spoofax.interpreter.core.Tools.isTermAppl;
import static org.spoofax.interpreter.core.Tools.termAt;

import org.apache.commons.vfs2.FileObject;
import org.metaborg.spoofax.core.context.ContextIdentifier;
import org.metaborg.spoofax.core.context.SpoofaxContext;
import org.metaborg.spoofax.core.language.ILanguage;
import org.metaborg.spoofax.core.language.ILanguageService;
import org.metaborg.spoofax.core.resource.ResourceService;
import org.metaborg.spoofax.core.stratego.StrategoRuntimeService;
import org.metaborg.sunshine.environment.ServiceRegistry;
import org.spoofax.interpreter.core.InterpreterException;
import org.spoofax.interpreter.core.UndefinedStrategyException;
import org.spoofax.interpreter.terms.IStrategoAppl;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.interpreter.terms.ITermFactory;
import org.strategoxt.HybridInterpreter;
import org.strategoxt.lang.Context;
import org.strategoxt.lang.Strategy;

/**
 * Evaluate a strategy in a stratego instance belonging to a language plugin.
 */
public class plugin_strategy_invoke_0_2 extends Strategy {
    public static final plugin_strategy_invoke_0_2 instance = new plugin_strategy_invoke_0_2();


    /**
     * @return Fail(trace) for strategy failure, Error(message) a string for errors, or Some(term) for success.
     */
    @Override public IStrategoTerm invoke(Context context, IStrategoTerm current, IStrategoTerm languageName,
        IStrategoTerm strategy) {
        final ITermFactory factory = context.getFactory();
        final ServiceRegistry env = ServiceRegistry.INSTANCE();
        final ILanguage lang = env.getService(ILanguageService.class).get(asJavaString(languageName));
        final FileObject location = env.getService(ResourceService.class).resolve(context.getIOAgent().getWorkingDir());
        final HybridInterpreter runtime =
            env.getService(StrategoRuntimeService.class).runtime(
                new SpoofaxContext(new ContextIdentifier(location, lang)));

        // strategy should be a String
        if(isTermAppl(strategy) && ((IStrategoAppl) strategy).getName().equals("Strategy"))
            strategy = termAt(strategy, 0);

        runtime.setCurrent(current);
        // TODO catch blocks copied from eclipse-specific code.
        // Why do we need them? Don't we want to fail fast?
        try {
            if(runtime.invoke(asJavaString(strategy))) {
                current = runtime.current();
                current = factory.makeAppl(factory.makeConstructor("Some", 1), current);
                return current;
            } else {
                Context foreignContext = runtime.getCompiledContext();
                String trace = "rewriting failed\n" + (foreignContext != null ? foreignContext.getTraceString() : "");
                return factory.makeAppl(factory.makeConstructor("Fail", 1), factory.makeString(trace));
            }
        } catch(UndefinedStrategyException e) {
            return factory.makeAppl(factory.makeConstructor("Error", 1),
                factory.makeString("Problem executing foreign strategy for testing: " + e.getLocalizedMessage()));
        } catch(InterpreterException e) {
            return factory.makeAppl(factory.makeConstructor("Error", 1), factory.makeString(e.getLocalizedMessage()));
        } catch(RuntimeException e) {
            return factory.makeAppl(factory.makeConstructor("Error", 1),
                factory.makeString(e.getClass().getName() + ": " + e.getLocalizedMessage() + " (see error log)"));
        }
    }
}

@@ -270,16 +270,67 @@
 Object;%0A
+import org.metaborg.spoofax.core.SpoofaxException;%0A
 import o
@@ -2027,18 +2027,31 @@
  runtime
- =
+;%0A        try %7B
 %0A       
@@ -2054,16 +2054,26 @@
         
+ runtime =
  env.get
@@ -2194,16 +2194,183 @@
 lang)));
+%0A        %7D catch(SpoofaxException e) %7B%0A            return factory.makeAppl(factory.makeConstructor(%22Error%22, 1), factory.makeString(e.getLocalizedMessage()));%0A        %7D
 %0A%0A      
@@ -2954,15 +2954,8 @@
    %7D
- else %7B
 %0A   
@@ -2963,20 +2963,35 @@
         
+%0A    
     
+    final 
 Context 
@@ -3049,19 +3049,21 @@
         
-   
+final
  String 
@@ -3162,36 +3162,32 @@
 %22);%0A            
-    
 return factory.m
@@ -3258,30 +3258,16 @@
 race));%0A
-            %7D%0A
         

Handle exception