import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
import org.apache.tools.ant.util.*;
import org.apache.tools.ant.taskdefs.*;

import java.io.*;
import java.util.*;
/**
 *	@author roxspring@yahoo.com
 */
public class DocCommentsTask
	extends Copy
{
	protected void validateAttributes()
		throws BuildException
	{
		super.validateAttributes();

		if(comment==null)
			throw new BuildException("A comment type is required");

		comment.validate();
	}

	private Comment comment = null;

	public Comment createLineComment()
	{
		if(comment==null)
			return comment = new LineComment();
		else
			throw new BuildException("Only one comment type can be used");

	}

	public Comment createBlockComment()
	{
		if(comment==null)
			return comment = new BlockComment();
		else
			throw new BuildException("Only one comment type can be used");

	}

	protected void doFileOperations()
	{
		FileNameMapper mapper = null;

		if(mapperElement==null)
			mapper = new IdentityMapper();
		else
			mapper = mapperElement.getImplementation();

		log("Processing " + fileCopyMap.size() +
			" file" + (fileCopyMap.size() == 1 ? "" : "s") +
			" to " + destDir.getAbsolutePath() );

		Enumeration e = fileCopyMap.keys();
		while(e.hasMoreElements())
		{
			String fromFile = (String) e.nextElement();
			String toFile = (String) fileCopyMap.get(fromFile);

			if( fromFile.equals( toFile ) ) {
				log("Skipping self-copy of " + fromFile, verbosity);
				continue;
			}

			try {
				log("Extracting from " + fromFile + " to " + toFile, verbosity);
				extractComments(new File(fromFile),new File(toFile));
			} catch (IOException ioe) {
				String msg = "Failed to extract from " + fromFile + " to " + toFile
					+ " due to " + ioe.getMessage();
				throw new BuildException(msg, ioe, location);
			}
		}
	}

	private void extractComments(File sourceFile, File destFile)
		throws IOException
	{
		if (forceOverwrite || !destFile.exists() ||
			destFile.lastModified() < sourceFile.lastModified())
		{

			File parent = new File(destFile.getParent());
			if (!parent.exists()) {
				parent.mkdirs();
			}

			if (destFile.exists() && destFile.isFile()) {
				destFile.delete();
			}

			boolean inComment = false;

			BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile)));
			PrintStream out = new PrintStream(new FileOutputStream(destFile));

			comment.extract(in,out);

			in.close();
			out.close();
		}
	}

	public abstract class Comment
	{
		public abstract void validate()
			throws BuildException;

		public abstract void extract(BufferedReader in, PrintStream out)
			throws IOException;
	}

	public class LineComment
		extends Comment
	{
		protected String prefix = null;

		public void setPrefix(String prefix)
		{
			this.prefix = prefix;
		}

		public void validate()
			throws BuildException
		{
			if(prefix==null)
				throw new BuildException("A comment prefix is required");
		}

		public void extract(BufferedReader in, PrintStream out)
			throws IOException
		{
			String line = in.readLine();
			int l = prefix.length();

			while(line!=null)
			{
				int i = line.indexOf(prefix);
				if(i>-1)
				{
					out.println(line.substring(i + prefix.length()));
				}
				line = in.readLine();
			}
		}
	}

	public class BlockComment
		extends Comment
	{
		private String prefix = null;
		private String postfix = null;
		private String linePrefix = null;

		public void setPrefix(String prefix)
		{
			this.prefix = prefix;
		}

		public void setPostfix(String postfix)
		{
			this.postfix = postfix;
		}

		public void setLinePrefix(String linePrefix)
		{
			this.linePrefix = linePrefix;
		}

		public void validate()
			throws BuildException
		{
			if(prefix==null)
				throw new BuildException("A comment prefix (eg: /**) is required");

			if(postfix==null)
				throw new BuildException("A comment postfix (eg: */) is required");
		}

		public void extract(BufferedReader in, PrintStream out)
			throws IOException
		{
			String line = in.readLine();
			int l = prefix.length();
			boolean inComment = false;

			//out = System.out;
			while(line!=null)
			{
				if(inComment)
				{
					String commentLine = line.trim();

					if(!commentLine.startsWith(postfix) &&
						commentLine.startsWith(linePrefix))
					{
						line = commentLine.substring(linePrefix.length());
					}


					inComment = extractComment(line,out,true);
				}
				else // !inComment
					inComment = extractComment(line,out,false);

				out.println();

				line = in.readLine();
			}
		}

		private boolean extractComment(String line,PrintStream out,boolean inComment)
		{
			//System.out.println("" + inComment +": " + line);
			if(inComment)
			{
				int i = line.indexOf(postfix);
				if(i>-1)
				{
					out.print(line.substring(0,i));
					return extractComment(line.substring(i+postfix.length()),out,false);
				}
				else
				{
					out.print(line);
					return true;
				}
			}
			else
			{
				int i = line.indexOf(prefix);
				if(i>-1)
				{
					return extractComment(line.substring(i+prefix.length()),out,true);
				}
				else
				{
					return false;
				}
			}
		}
	}
}

