/**
 * 
 */
package org.strategoxt.imp.runtime.services;

import static org.spoofax.interpreter.core.Tools.asJavaString;
import static org.spoofax.interpreter.core.Tools.isTermString;
import static org.spoofax.interpreter.core.Tools.isTermTuple;
import static org.spoofax.interpreter.core.Tools.termAt;
import static org.strategoxt.imp.runtime.dynamicloading.TermReader.cons;

import java.io.File;
import java.io.IOException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.DocumentEvent;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.strategoxt.imp.runtime.EditorState;
import org.strategoxt.imp.runtime.Environment;
import org.strategoxt.imp.runtime.dynamicloading.IOnSaveService;
import org.strategoxt.imp.runtime.parser.ast.AstMessageHandler;
import org.strategoxt.imp.runtime.stratego.EditorIOAgent;
import org.strategoxt.imp.runtime.stratego.RefreshResourcePrimitive;
import org.strategoxt.imp.runtime.stratego.SourceAttachment;

/**
 * @author Lennart Kats <lennart add lclnet.nl>
 */
public class OnSaveService implements IOnSaveService {

	private final StrategoObserver runtime;
	
	private final String function;
	
	private EditorState editor;
	
	public OnSaveService(StrategoObserver runtime, String function) {
		this.runtime = runtime;
		this.function = function;
	}
	
	public void initialize(EditorState editor) {
		this.editor = editor;
	}

	public void documentAboutToBeChanged(DocumentEvent event) {
		// Unused
	}

	public void documentChanged(DocumentEvent event) {
		if (function == null) return;
		
		//String contents = event.getDocument().get();

		IStrategoTerm ast = editor.getCurrentAst();
		invokeOnSave(ast);
	}

	public void invokeOnSave(IStrategoTerm ast) {
        if (ast == null || function == null) return;
        
		try {
			Environment.getStrategoLock().lock();
			try {
				IStrategoTerm result = runtime.invokeSilent(function, ast);
				if (result == null) {
					runtime.reportRewritingFailed();
					String log = runtime.getLog();
					Environment.logException(log.length() == 0 ? "Analysis failed" : "Analysis failed:\n" + log);
					AstMessageHandler messages = runtime.getMessages();
					messages.clearMarkers(SourceAttachment.getResource(ast));
					messages.addMarkerFirstLine(SourceAttachment.getResource(ast), "Analysis failed (see error log)", IMarker.SEVERITY_ERROR);
					messages.commitAllChanges();
				} else if (isTermString(result)) {
					// Function's returning a filename
					String file = asJavaString(result);
					if (new File(file).exists())
						RefreshResourcePrimitive.call(runtime.getRuntime().getContext(), file);	
				} else if (isTermTuple(result) && result.getSubtermCount() == 2 && isTermString(termAt(result, 0)) && isTermString(termAt(result, 1))) {
					// Function's returning a tuple like a builder
					// let's be friendly and try to refresh the file
					String file = asJavaString(termAt(result, 0));
					String newContents = asJavaString(termAt(result, 1));
					try {
						IFile resource = EditorIOAgent.getFile(runtime.getRuntime().getContext(), file);
						StrategoBuilder.setFileContentsDirect(resource, newContents);
					} catch (IOException e) {
						Environment.logException("Problem when handling on save event", e);
					} catch (CoreException e) {
						Environment.logException("Problem when handling on save event", e);
					}
				} else if (!"None".equals(cons(result))) {
					if (editor != null && editor.getDescriptor().isDynamicallyLoaded())
						Environment.logWarning("Unexpected result from 'on save' strategy: should be None() or (\"filename\", \"contents\"): " + result);
				}
			} finally {
				Environment.getStrategoLock().unlock();
			}
		} catch (RuntimeException e) {
			Environment.logException("Exception in OnSaveService", e);
		} catch (Error e) {
			Environment.logException("Exception in OnSaveService", e);
		}
	}

}

@@ -738,24 +738,97 @@
 nvironment;%0A
+import org.strategoxt.imp.runtime.dynamicloading.BadDescriptorException;%0A
 import org.s
@@ -1723,58 +1723,23 @@
 %09%0A%09%09
-//String contents = event.getDocument().get();%0A%0A%09%09
+try %7B%0A%09%09%09final 
 IStr
@@ -1768,15 +1768,16 @@
 .get
-Current
+Analyzed
 Ast(
@@ -1781,16 +1781,17 @@
 st();%0A%09%09
+%09
 invokeOn
@@ -1801,16 +1801,124 @@
 e(ast);%0A
+%09%09%7D catch(BadDescriptorException e) %7B%0A%09%09%09Environment.logException(%22Could not call on-save handler%22, e);%0A%09%09%7D%0A
 %09%7D%0A%0A%09pub

Use the analysed AST for the on-save service, this will cause a file to be analyzed twice if the analysed AST is not available at the time of saving.