//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/willow
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : willow@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.workflow.script.compiler;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import org.huihoo.workflow.WorkflowException;
import org.huihoo.workflow.script.Constants;
import org.huihoo.workflow.script.ScriptCompilationContext;
import org.huihoo.workflow.util.StringManager;

public class ScriptParseEventListener implements ParseEventListener
{
	protected static StringManager sm = StringManager.getManager(Constants.RESOURCE_BUNDLE_BASE);
	protected ScriptReader reader;
	protected ScriptWriter writer;
	protected ScriptCompilationContext ctxt;
	protected Vector imports = new Vector();
	protected Vector generators = new Vector();
	String error = "";
	int bufferSize = Constants.DEFAULT_BUFFER_SIZE;
	protected ScriptParseEventListener(ScriptReader reader, ScriptWriter writer)
	{
		this.reader = reader;
		this.writer = writer;
	}
	final void addGenerator(Generator gen) throws WorkflowException
	{
		gen.init(ctxt);
		generators.addElement(gen);
	}
	ScriptParseEventListener(ScriptCompilationContext ctxt)
	{
		this.ctxt = ctxt;
		this.reader = this.ctxt.getReader();
		this.writer = this.ctxt.getWriter();
	}
	public void beginScriptProcessing() throws WorkflowException
	{
		for (int i = 0; i < Constants.STANDARD_IMPORTS.length; i++)
			imports.addElement(Constants.STANDARD_IMPORTS[i]);
	}
	public void endScriptProcessing() throws WorkflowException
	{
		generateHeader();
		writer.println();
		generateAll(EvaluteMethodPhase.class);
		writer.println();
		generateFooter();
	}
	private void generateAll(Class phase) throws WorkflowException
	{
		for (int i = 0; i < generators.size(); i++)
		{
			Generator gen = (Generator) generators.elementAt(i);
			if (phase.isInstance(gen))
			{
				gen.generate(writer, phase);
			}
		}
	}
	private void generateHeader() throws WorkflowException
	{
		String scriptPackageName = ctxt.getScriptPackageName();
		String scriptClassName = ctxt.getScriptClassName();
		String evaluteMethodName = Constants.EVALUTE_METHOD_NAME;
		// First the package name:
		if (!"".equals(scriptPackageName) && scriptPackageName != null)
		{
			writer.println("package " + scriptPackageName + ";");
			writer.println();
		}
		Enumeration e = imports.elements();
		while (e.hasMoreElements())
			writer.println("import " + (String) e.nextElement() + ";");
		writer.println();
		writer.print("final public class " + scriptClassName + " extends ");
		writer.print(Constants.SCRIPT_BASE_CLASS);
		
		writer.println(" {");
		writer.pushIndent();
		writer.println();
		writer.println("public " + scriptClassName + "( ) ");
		writer.println("{");
		writer.println("}");
		writer.println();
		writer.println("public void __scriptInit()");
		writer.println("{");
		writer.println("}");
		writer.println();
		writer.println("public boolean " + evaluteMethodName + "(" + "WorkflowWork workflowWork, WorkflowTransition workflowTransition,SelectorContext context)");
		writer.println("    throws SelectorException,IOException ");
		writer.println("{");
		writer.pushIndent();
		writer.println();
		writer.println("try");
		writer.println("{");
	}
	private void generateFooter() throws WorkflowException
	{
		writer.popIndent();
		writer.println("}");
		writer.println("catch (Exception ex)");
		writer.println("{");
		writer.pushIndent();
		writer.println("if ((ex instanceof SelectorException))");
		writer.println("{");
		writer.pushIndent();
		writer.println("throw (SelectorException)ex;");
		writer.popIndent();
		writer.println("}");
		writer.println("else if ((ex instanceof IOException))");
		writer.println("{");
		writer.pushIndent();
		writer.println("throw (IOException)ex;");
		writer.popIndent();
		writer.println("}");
		writer.println("else");
		writer.println("{");
		writer.pushIndent();
		writer.println("throw new SelectorException(ex);");
		writer.popIndent();
		writer.println("}");
		writer.popIndent();
		writer.println("}");
		// Close the evalute method:
		writer.popIndent();
		writer.println("}");
		// Close the class definition:
		writer.popIndent();
		writer.println("}");
	}
	interface ScriptDirectiveHandler
	{
		void handleScriptDirectiveAttribute(ScriptParseEventListener listener, String value, Mark start, Mark stop)
			throws WorkflowException;
	}
	static final class ScriptDirectiveHandlerInfo
	
	{
		String attribute;
		ScriptDirectiveHandler handler;
		ScriptDirectiveHandlerInfo(String attribute, ScriptDirectiveHandler handler)
		{
			this.attribute = attribute;
			this.handler = handler;
		}
	}
	class GeneratorWrapper implements Generator, EvaluteMethodPhase
	{
		Generator generator;
		Mark start, stop;
		GeneratorWrapper(Generator generator, Mark start, Mark stop)
		{
			this.generator = generator;
			this.start = start;
			this.stop = stop;
		}
		public boolean generateCoordinates(Class phase)
		{
			return generator.generateCoordinates(phase);
		}
		public void init(ScriptCompilationContext ctxt) throws WorkflowException
		{
			generator.init(ctxt);
		}
		public void generate(ScriptWriter out, Class phase) throws WorkflowException
		{
			if (phase.isInstance(generator))
			{
				boolean genCoords = generator.generateCoordinates(phase);
				generator.generate(out, phase);
			}
		}
	}
	static final String importStr = "import";
	ScriptDirectiveHandlerInfo[] pdhis =
		new ScriptDirectiveHandlerInfo[] { new ScriptDirectiveHandlerInfo(importStr, new ImportsHandler())};
	static final class ImportsHandler implements ScriptDirectiveHandler
	{
		public void handleScriptDirectiveAttribute(
			ScriptParseEventListener listener,
			String importPkgs,
			Mark start,
			Mark stop)
			throws WorkflowException
		{
			if (importPkgs != null)
			{
				StringTokenizer tokenizer = new StringTokenizer(importPkgs, ",");
				while (tokenizer.hasMoreTokens())
					listener.imports.addElement(tokenizer.nextToken());
			}
		}
	}
	public void handleDirective(String directive, Mark start, Mark stop, Hashtable attrs) throws WorkflowException
	{
		if (directive.equals("page"))
		{
			Enumeration e = attrs.keys();
			String attr;
			while (e.hasMoreElements())
			{
				attr = (String) e.nextElement();
				for (int i = 0; i < pdhis.length; i++)
				{
					ScriptDirectiveHandlerInfo pdhi = pdhis[i];
					if (attr.equals(pdhi.attribute))
					{
						String value = (String) attrs.get(pdhi.attribute);
						pdhi.handler.handleScriptDirectiveAttribute(this, value, start, stop);
					}
				}
			}
		}
	}
	public void handleScriptlet(Mark start, Mark stop, Hashtable attrs) throws WorkflowException
	{
		Generator gen = new GeneratorWrapper(new ScriptletGenerator(reader.getChars(start, stop)), start, stop);
		addGenerator(gen);
	}
	public void handleCharData(Mark start, Mark stop, char[] chars) throws WorkflowException
	{
		GeneratorBase cdg;
		cdg = new CharDataGenerator(chars);
		Generator gen = new GeneratorWrapper(cdg, start, stop);
		addGenerator(gen);
	}
}
