
package injection;

import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.lang.reflect.Modifier;

public final class Instrumentor implements InjectionConsumer
{
	private final Writer output;
	
	/**
	 * Holds several properties of the class currently
	 * worked on.
	 */
	private JavaClass class_state=null;
	
	/**
	 * Collects the class states of outer classes,
	 * when operating on a inner class.
	 * @see #class_state
	 * @element-type InstrumentorClass
	 */
	private ArrayList class_state_stack=new ArrayList();
	
	protected final String lineSeparator;
	
	/**
	 * The last file level doccomment that was read.
	 */
	private String m_sFileDocComment = null;
	
	public Instrumentor(Writer output)
	{
		this.output=output;
		
		final String systemLineSeparator = System.getProperty("line.separator");
		if(systemLineSeparator==null)
		{
			System.out.println("warning: property \"line.separator\" is null, using LF (unix style).");
			lineSeparator = "\n";
		}
		else
			lineSeparator = systemLineSeparator;
	}
	
	public void onPackage(JavaFile javafile)
	throws InjectorParseException
	{
	}
	
	public void onImport(String importname)
	{
	}
	
	private boolean discardnextfeature=false;
	
	private static final String PERSISTENT_CLASS = "persistent";
	private static final String PERSISTENT_ATTRIBUTE = PERSISTENT_CLASS;
	
	private void handleClassComment(final JavaClass jc, final String docComment)
	{
		if(docComment.indexOf('@'+PERSISTENT_CLASS)>=0)
			jc.setPersistent();
	}
	
	public void onClass(final JavaClass jc)
	{
		System.out.println("onClass("+jc.getName()+")");

		discardnextfeature=false;
		
		class_state_stack.add(class_state);
		class_state=jc;
		
		if (m_sFileDocComment != null)
		{
			handleClassComment(jc, m_sFileDocComment);
			m_sFileDocComment = null; // mark as handled.
		}
	}
	
	private void writeAccessMethods(final JavaAttribute persistentAttribute)
	throws IOException
	{
		output.write("//");
		output.write(persistentAttribute.getName());
		output.write(" ");
		output.write(Modifier.toString(persistentAttribute.getModifiers()));
		output.write(" ");
		output.write(persistentAttribute.getType());
		output.write(" ");
		output.write(Modifier.toString(persistentAttribute.getMethodModifiers()));
		output.write(lineSeparator);
	}
	
	public void onClassEnd(JavaClass jc)
	throws IOException, InjectorParseException
	{
		System.out.println("onClassEnd("+jc.getName()+")");

		if(!jc.isInterface() && jc.isPersistent())
		{
			for(Iterator i = jc.getPersistentAttributes().iterator(); i.hasNext(); )
			{
				// write setter/getter methods
				final JavaAttribute persistentAttribute = (JavaAttribute)i.next();
				writeAccessMethods(persistentAttribute);
			}
		}
		
		if(class_state!=jc)
			throw new RuntimeException();
		class_state=(JavaClass)(class_state_stack.remove(class_state_stack.size()-1));
	}
	
	public void onBehaviourHeader(JavaBehaviour jb)
	throws java.io.IOException
	{
		output.write(jb.getLiteral());
	}
	
	public void onAttributeHeader(JavaAttribute ja)
	{
	}
	
	public void onClassFeature(final JavaFeature jf, final String docComment)
	throws IOException, InjectorParseException
	{
		System.out.println("onClassFeature("+jf.getName()+" "+docComment+")");
		if(!class_state.isInterface())
		{
			if(jf instanceof JavaAttribute &&
			Modifier.isFinal(jf.getModifiers()) &&
			Modifier.isStatic(jf.getModifiers()) &&
			!discardnextfeature &&
			docComment!=null &&
			docComment.indexOf('@'+PERSISTENT_ATTRIBUTE)>=0)
			{
				((JavaAttribute)jf).makePersistent();
			}
		}
		discardnextfeature=false;
	}
	
	public boolean onDocComment(String docComment)
	throws IOException
	{
		System.out.println("onDocComment("+docComment+")");

		if(OCL_AUTHOR.equals(Injector.findDocTag(docComment, "author")))
		{
			discardnextfeature=true;
			return false;
		}
		else
		{
			output.write(docComment);
			return true;
		}
	}
	
	public void onFileDocComment(String docComment)
	throws IOException
	{
		System.out.println("onFileDocComment("+docComment+")");
		
		output.write(docComment);
		
		if (class_state != null)
		{
			// handle doccomment immediately
			handleClassComment(class_state, docComment);
		}
		else
		{
			// remember to be handled as soon as we know what class we're talking about
			m_sFileDocComment = docComment;
		}
	}
	
	public void onFileEnd()
	{
		if(!class_state_stack.isEmpty())
			throw new RuntimeException();
	}
	
	/**
	 * All generated class features get this string as author.
	 * Must not contain spaces, line breaks or askerics.
	 * @see Injector#findDocTag
	 */
	public static final String OCL_AUTHOR="ocl_injector";
	
}



@@ -1342,24 +1342,147 @@
 NT_CLASS;%0A%09%0A
+%09/**%0A%09 * All generated class features get this doccomment tag.%0A%09 */%0A%09private static final String GENERATED = %22generated%22;%0A%0A
 %09private voi
@@ -1555,39 +1555,40 @@
 %09%7B%0A%09%09if(
-docComment.indexOf('@'+
+containsTag(docComment, 
 PERSISTE
@@ -1596,19 +1596,16 @@
 T_CLASS)
-%3E=0
 )%0A%09%09%09jc.
@@ -3549,54 +3549,32 @@
 %0A%09%09%09
-docComment!=null &&%0A%09%09%09docComment.indexOf('@'+
+containsTag(docComment, 
 PERS
@@ -3594,11 +3594,8 @@
 UTE)
-%3E=0
 )%0A%09%09
@@ -3816,42 +3816,16 @@
 %09if(
-OCL_AUTHOR.equals(Injector.findDoc
+contains
 Tag(
@@ -3840,17 +3840,17 @@
 nt, 
-%22author%22)
+GENERATED
 ))%0A%09
@@ -4489,216 +4489,168 @@
 %0A%09%0A%09
-/**%0A%09 * All generated class features get this string as author.%0A%09 * Must not contain spaces, line breaks or askerics.%0A%09 * @see Injector#findDocTag%0A%09 */%0A%09public static final String OCL_AUTHOR=%22ocl_injector%22
+private static final boolean containsTag(final String docComment, final String tagName)%0A%09%7B%0A%09%09return docComment!=null && docComment.indexOf('@'+tagName)%3E=0 
 ;%0A%09
+%7D%0A
 %0A%7D%0A%0A

use @generated instead of ocl_author