

package synergynetframework.appsystem.launcher.distbuilder;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.NoSuchAlgorithmException;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import synergynetframework.utils.crypto.CryptoUtils;

/**
 * The Class DistBuilder.
 */
public class DistBuilder extends Task {
	
	/** The atts. */
	private static AttributesImpl atts;

	/** The hd. */
	private static TransformerHandler hd;

	/** The out. */
	static PrintWriter out;

	/**
	 * Process directory.
	 *
	 * @param root
	 *            the root
	 * @param d
	 *            the d
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 * @throws NoSuchAlgorithmException
	 *             the no such algorithm exception
	 * @throws SAXException
	 *             the SAX exception
	 */
	public static void processDirectory(File root, File d) throws IOException,
			NoSuchAlgorithmException, SAXException {
		int charsToRemove = root.getCanonicalPath().length();
		String dir = d.getCanonicalPath().substring(charsToRemove);
		if (dir.length() > 0) {
			writeDirEntry(dir);
		} else {
			writeDirEntry("/");
		}
		
		File[] directories = d.listFiles(new FileFilter() {
			public boolean accept(File t) {
				return t.isDirectory();
			}
		});
		
		File[] files = d.listFiles(new FileFilter() {
			
			public boolean accept(File t) {
				return t.isFile();
			}
			
		});
		for (File x : files) {
			writeFileEntry(x.getCanonicalPath().substring(charsToRemove),
					CryptoUtils.md5(x));
		}
		
		for (File x : directories) {
			processDirectory(root, x);
		}
	}

	/**
	 * Write dir entry.
	 *
	 * @param dir
	 *            the dir
	 * @throws SAXException
	 *             the SAX exception
	 */
	private static void writeDirEntry(String dir) throws SAXException {
		atts.clear();
		atts.addAttribute("", "", "path", "CDATA", dir);
		hd.startElement("", "", "directory", atts);
		hd.endElement("", "", "directory");
	}
	
	/**
	 * Write file entry.
	 *
	 * @param path
	 *            the path
	 * @param md5
	 *            the md5
	 * @throws SAXException
	 *             the SAX exception
	 */
	private static void writeFileEntry(String path, String md5)
			throws SAXException {
		atts.clear();
		atts.addAttribute("", "", "path", "CDATA", path);
		atts.addAttribute("", "", "md5", "CDATA", md5);
		hd.startElement("", "", "file", atts);
		// hd.characters(info.toCharArray(),0,info.length());
		hd.endElement("", "", "file");
	}

	/** The outfile. */
	private File outfile;
	
	/** The source dir. */
	private File sourceDir;
	
	/*
	 * (non-Javadoc)
	 * @see org.apache.tools.ant.Task#execute()
	 */
	public void execute() throws BuildException {
		System.out.println(sourceDir.getAbsolutePath());
		System.out.println(outfile.getAbsolutePath());
		
		try {
			out = new PrintWriter(outfile);
			StreamResult streamResult = new StreamResult(out);
			SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory
					.newInstance();
			hd = tf.newTransformerHandler();
			Transformer serializer = hd.getTransformer();
			serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			serializer.setOutputProperty(OutputKeys.INDENT, "yes");
			hd.setResult(streamResult);
			hd.startDocument();
			atts = new AttributesImpl();
			
			hd.startElement("", "", "distribution", atts);
			
			if (!sourceDir.isDirectory()) {
				throw new Exception("Argument is not a directory.");
			}
			
			processDirectory(sourceDir, sourceDir);

			hd.endElement("", "", "distribution");
			hd.endDocument();

			out.close();
		} catch (FileNotFoundException e) {
			// e.printStackTrace();
			throw new BuildException(e);
		} catch (SAXException e) {
			// e.printStackTrace();
			throw new BuildException(e);
		} catch (NoSuchAlgorithmException e) {
			// e.printStackTrace();
			throw new BuildException(e);
		} catch (IOException e) {
			// e.printStackTrace();
			throw new BuildException(e);
		} catch (Exception e) {
			// e.printStackTrace();
			throw new BuildException(e);
		}
		
	}
	
	/**
	 * Sets the outfile.
	 *
	 * @param outfile
	 *            the new outfile
	 */
	public void setOutfile(File outfile) {
		this.outfile = outfile;
	}
	
	/**
	 * Sets the sourcedir.
	 *
	 * @param sourceDir
	 *            the new sourcedir
	 */
	public void setSourcedir(File sourceDir) {
		this.sourceDir = sourceDir;
	}
	
}
