package entitygen;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

/** For a given Entity class, we generate some artifacts:
 * <ul>
 * <li>Home class - extends EntityHome<Entity,Long>
 * <li>List class - interface extends Repository
 * <li>List Page - xhtml
 * <li>Detail Page - xhtml
 * <li>Edit Page - xhtml
 * </ul>
 * @author ian
 *
 */
public class JenGen {
	
	// Things that will need to be parameterized
	final static String OUTPUT_DIR = "../entitygenoutput";
	final static String demoClassName = "model.MiniPerson";
	
	final static String SRC_DIR = "src/main/java";
	final static String WEB_DIR = "src/main/webapp";
	final static String PKG_NAME = "com.example.data";
	
	final static String homeClassFilePattern = "%s/%sHome.java",
		listClassFilePattern = "%s/%sList.java",
		listPageFilePattern = "%sList.xhtml",
		viewPageFilePattern = "%sView.xhtml",
		editPageFilePattern = "%sEdit.xhtml";

	public static void main(String[] args) throws Exception {
		if (args.length == 2 ) {
			String dir = args[0];
			String className = args[1];
			String fileName = dir + "/" + className.replaceAll("\\.", "/") + ".class";
			process(className, fileName);
		} else {
			System.err.println("Usage: JenGen classDir className");
		}
	}

	private static void process(String className, String fileName) throws Exception {
		System.out.println("Processing " + className);
		
		// Do this first - most likely to fail
		Class<?> clazz = new FileClassLoader().nameToClass(className, fileName);
		
		VelocityEngine engine = new VelocityEngine();
		// See http://stackoverflow.com/questions/9051413/unable-to-find-velocity-template-resources
		engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
		engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
		engine.init();

		VelocityContext context = new VelocityContext();

		String pkgDir = PKG_NAME.replace('.', '/');
		final File x = new File(OUTPUT_DIR + "/" + SRC_DIR, pkgDir);
		ensureDirectoryExists(x);
		final File y = new File(OUTPUT_DIR + "/" + WEB_DIR);
		ensureDirectoryExists(y);
		
		
		context.put("entityClazz", clazz);
		final String simpleName = clazz.getSimpleName();
		context.put("EntityClassUC", simpleName);
		context.put("EntityClassLC", toBeanName(clazz.getSimpleName()));
		context.put("pkg_name", PKG_NAME);

		// Java Code
		Template homeClassTemplate = engine.getTemplate("HomeClass.vm");
		Template listClassTemplate = engine.getTemplate("ListClass.vm");

		// Pages
		Template listPageTemplate = engine.getTemplate("ListPage.vm");
		Template viewPageTemplate = engine.getTemplate("ViewPage.vm");
		Template editPageTemplate = engine.getTemplate("EditPage.vm");
		
		renderFile(context, OUTPUT_DIR + "/" + SRC_DIR, String.format(homeClassFilePattern, pkgDir, simpleName), homeClassTemplate);
		renderFile(context, OUTPUT_DIR + "/" + SRC_DIR, String.format(listClassFilePattern, pkgDir, simpleName), listClassTemplate);
		
		renderFile(context, OUTPUT_DIR + "/" + WEB_DIR, String.format(listPageFilePattern, simpleName), listPageTemplate);
		renderFile(context, OUTPUT_DIR + "/" + WEB_DIR, String.format(viewPageFilePattern, simpleName), viewPageTemplate);
		renderFile(context, OUTPUT_DIR + "/" + WEB_DIR, String.format(editPageFilePattern, simpleName), editPageTemplate);

		System.out.println("Done.");
	}

	/**
	 * Velocity Merge of one file and write it to output.
	 * @param context The Velocity Context
	 * @param dirName The top-level directory
	 * @param pathName The subdirectory and filename
	 * @param template The Velocity template
	 * @throws IOException if there's a problem here.
	 */
	public static void renderFile(VelocityContext context, 
			String dirName, String pathName,
			Template template)
			throws IOException {
		File classFile = new File(dirName, pathName);
		PrintWriter classWriter = new PrintWriter(classFile);
		template.merge(context, classWriter);
		classWriter.close();
	}

	/**
	 * @param x
	 * @throws IOException
	 */
	public static void ensureDirectoryExists(final File x) throws IOException {
		x.mkdirs();
		if (!x.isDirectory()) {
			throw new IOException("Can't create " + x);
		}
	}

	static String toBeanName(String name) {
		if (name == null || name.length() == 0) {
			throw new IllegalArgumentException("toBeanName(empty string)");
		}
		char ch = Character.toLowerCase(name.charAt(0));
		if (name.length() == 1) {
			return new String(new char[] {ch});
		}
		return ch + name.substring(1);
	}
}

@@ -1264,17 +1264,17 @@
 .length 
-=
+!
 = 2 ) %7B%0A
@@ -1281,61 +1281,86 @@
 %09%09%09S
-tring dir = args%5B0%5D;%0A%09%09%09String className = args%5B1%5D
+ystem.err.println(%22Usage: JenGen classDir className%22);%0A%09%09%09System.exit(1)
 ;%0A%09
+%09%7D%0A
 %09%09St
@@ -1368,165 +1368,119 @@
 ing 
-fileName = dir + %22/%22 + className.replaceAll(%22%5C%5C.%22, %22/%22) + %22.class%22;%0A%09%09%09process(className, fileName);%0A%09%09%7D else %7B%0A%09%09%09System.err.println(%22Usage: JenGen classDir
+dir = args%5B0%5D;%0A%09%09ClassLoader loader = new FileClassLoader(dir);%0A%09%09String className = args%5B1%5D;%0A%09%09process(loader,
  cla
@@ -1485,24 +1485,19 @@
 lassName
-%22
 );%0A
-%09%09%7D%0A
 %09%7D%0A%0A%09pri
@@ -1521,32 +1521,34 @@
 process(
-String className
+ClassLoader loader
 , String
@@ -1548,20 +1548,21 @@
  String 
-file
+class
 Name) th
@@ -1694,36 +1694,19 @@
 z = 
-new FileClassLoader().nameTo
+loader.load
 Clas
@@ -1720,18 +1720,8 @@
 Name
-, fileName
 );%0A%09

Improve use of classloader.