package com.mkyong.helloworld.domain.builder.generator;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.mkyong.helloworld.domain.KokyakuKojinDomain;

import freemarker.template.Configuration;
import freemarker.template.TemplateException;

public class BuilderGenerater {

	private static String TEMPLATE_FILE = "BuilderTemplate.ftl";
	private static String DESTINATION = "generated/";

	@SuppressWarnings("rawtypes")
	static Class TARGET_CLASS = KokyakuKojinDomain.class;

	public static void main(String[] args) {

		// get domain private fields
		List<Field> privateFields = new ArrayList<>();
		Field[] allFields = TARGET_CLASS.getDeclaredFields();
		for (Field field : allFields) {
			if (Modifier.isPrivate(field.getModifiers())) {
				privateFields.add(field);
			}
		}

		// config
		DomainConfig domainConfig = new DomainConfig();
		domainConfig.setBuilderBaseClass("AbstractDomainBuilder");
		domainConfig.setDomain(TARGET_CLASS.getSimpleName().replaceAll("Domain$", ""));
		ArrayList<HashMap<String, String>> members = new ArrayList<HashMap<String, String>>();
		for (Field m : privateFields) {
			HashMap<String, String> map = new HashMap<String, String>();
			map.put("type", m.getType().getName());
			map.put("name", m.getName());
			map.put("explain", m.getName());
			members.add(map);
		}
		domainConfig.setMembers(members);

		// configuration
		Configuration fileMarkerConfig = new Configuration(Configuration.VERSION_2_3_23);
		fileMarkerConfig.setClassForTemplateLoading(BuilderGenerater.class, "/");

		try {

			// template
			freemarker.template.Template template = fileMarkerConfig.getTemplate(TEMPLATE_FILE);

			// map
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("builderBaseClass", domainConfig.getBuilderBaseClass());
			map.put("domain", domainConfig.getDomain());
			map.put("members", domainConfig.getMembers());

			StringBuilder memberListWithComma = new StringBuilder();
			for (HashMap<String, String> m : domainConfig.getMembers()) {
				memberListWithComma.append("," + m.get("name"));
			}
			map.put("memberListWithComma", memberListWithComma.toString().replaceAll("^,", ""));

			// write
			File file = new File(DESTINATION + domainConfig.getDomain() + "DomainBuilder.java");
			PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));
			template.process(map, writer);

		} catch (IOException | TemplateException e) {
			e.printStackTrace();
		}
		System.out.println("Success!!");
	}

}

@@ -352,16 +352,68 @@
 l.Map;%0A%0A
+import com.mkyong.helloworld.domain.AbstractDomain;%0A
 import c
@@ -448,24 +448,34 @@
 KokyakuKojin
+TantoBusho
 Domain;%0A%0Aimp
@@ -779,16 +779,26 @@
 akuKojin
+TantoBusho
 Domain.c
@@ -933,15 +933,24 @@
 ;%0A%09%09
+ArrayList%3C
 Field
-%5B%5D
+%3E
  all
@@ -962,41 +962,424 @@
 s = 
-TARGET_CLASS.getDeclaredFields();
+new ArrayList%3CField%3E();%0A%09%09for (Field f : TARGET_CLASS.getDeclaredFields()) %7B%0A%09%09%09allFields.add(f);%0A%09%09%7D%0A%0A%09%09// get domain parent private fields if exists%0A%09%09Class%3C?%3E parent = TARGET_CLASS.getSuperclass();%0A%09%09while (parent != null) %7B%0A%09%09%09if (!AbstractDomain.class.isAssignableFrom(parent)) %7B%0A%09%09%09%09break;%0A%09%09%09%7D%0A%09%09%09for (Field f : parent.getDeclaredFields()) %7B%0A%09%09%09%09allFields.add(f);%0A%09%09%09%7D%0A%09%09%09parent = parent.getSuperclass();%0A%09%09%7D%0A
 %0A%09%09f

fix for domain with super class