package jp.cssj.anttask;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import jp.cssj.cti.helpers.AbortException;
import jp.cssj.cti.helpers.ContentBuilder;
import jp.cssj.cti.helpers.FileContentBuilder;
import jp.cssj.cti.helpers.StdioErrorHandler;
import jp.cssj.cti.resolver.Source;
import jp.cssj.cti.resolver.SourceResolver;
import jp.cssj.cti.resolver.URISourceResolver;
import jp.cssj.cti.transcoder.Transcoder;
import jp.cssj.cti.transcoder.TranscoderException;
import jp.cssj.cti.transcoder.TranscoderFactory;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.IdentityMapper;
import org.apache.tools.ant.util.SourceFileScanner;

/**
 * CSSJで文書を変換するタスクです。
 * 
 * @author <a href="mailto:miyabe at gnn.co.jp">MIYABE Tatsuhiko </a>
 * @version $Id: CSSJTask.java,v 1.3 2005/08/18 04:51:26 harumanx Exp $
 */
public class CSSJTask extends MatchingTask {
	protected Transcoder transcoder = TranscoderFactory.newTranscoderFactory()
			.newTranscoder();

	protected SourceResolver resolver = new URISourceResolver();

	protected List props = new ArrayList();

	protected File srcDir, destDir;

	protected String suffix = ".pdf";

	protected int count = 0;

	public class Property {
		public String name, value;

		public void setName(String name) {
			this.name = name;
		}

		public void setValue(String value) {
			this.value = value;
		}
	}

	public void setResources(String resources) {
		System.setProperty("jp.cssj.resources.dir", this.getProject()
				.resolveFile(resources).getAbsolutePath());
	}

	public Property createProperty() {
		Property prop = new Property();
		this.props.add(prop);
		return prop;
	}

	public void setSrcDir(File srcDir) {
		this.srcDir = srcDir;
	}

	public void setDestDir(File destDir) {
		this.destDir = destDir;
	}

	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

	private FileNameMapper myMapper = new IdentityMapper() {
		public String[] mapFileName(String src) {
			return new String[] { CSSJTask.this.map(src) };
		}
	};

	protected String map(String src) {
		String dest;
		int dot = src.lastIndexOf('.');
		if (dot != -1) {
			dest = src.substring(0, dot) + this.suffix;
		} else {
			dest = src + this.suffix;
		}
		return dest;
	}

	public void execute() throws BuildException {
		Properties props = new Properties();
		for (int i = 0; i < this.props.size(); ++i) {
			Property prop = (Property) this.props.get(i);
			props.setProperty(prop.name, prop.value);
		}

		File srcDir;
		if (this.srcDir == null) {
			srcDir = this.getProject().resolveFile(".");
		} else {
			srcDir = this.srcDir;
		}

		File destDir;
		if (this.destDir == null) {
			destDir = srcDir;
		} else {
			destDir = this.destDir;
		}

		DirectoryScanner ds = this.getDirectoryScanner(srcDir);
		String[] files = ds.getIncludedFiles();
		SourceFileScanner sfs = new SourceFileScanner(this);
		files = sfs.restrict(files, srcDir, this.destDir, myMapper);
		try {
			for (int i = 0; i < files.length; ++i) {
				String src = files[i];
				String dest = this.map(src);
				this.convert(new File(srcDir, src), new File(destDir, dest),
						props);
			}
		} catch (Exception e) {
			throw new BuildException(e);
		} finally {
			System.out.println("Transcoded " + this.count + " file(s).");
		}
	}

	private void convert(File src, File dest, Properties props)
			throws IOException, TranscoderException, AbortException {
		if (dest.exists() && dest.lastModified() >= src.lastModified()) {
			return;
		}
		System.out.println(src.getName() + " -> " + dest.getName());

		dest.getParentFile().mkdirs();
		OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
		try {
			ContentBuilder builder = new FileContentBuilder(out);
			try {
				Source source = this.resolver.resolve(src.toURL().toString());
				try {
					this.transcoder.transcode(builder, source, this.resolver,
							props, StdioErrorHandler.getInstance());
				} finally {
					this.resolver.release(source);
				}
			} finally {
				builder.finish();
			}
		} finally {
			out.close();
		}
		this.count++;
	}
}
