package hibergui.generator;

import java.io.*;
import java.util.*;
import java.util.logging.Logger;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import freemarker.template.*;
import hibergui.HiberGUI;
import hibergui.generator.tool.xml.*;

/**
 * Generates java source code from XML documents with
 * using FreeMarker toolkit.
 * 
 * @author Csaba Gyenge
 */
public class Generator {
	private static final String TEMPLATES_FOLDER = "template";
	private static final String TEMPLATE_FILENAME = "test.ftl";
	
	private static final String DEFAULT_DESTDIR = "";
	
	private static final Logger logger;
	
	static {
		logger = Logger.getLogger(Generator.class.getName());
	}
	
	/**
	 * Generates java source code.
	 * 
	 * @param configXML
	 *            Path to the configuration xml file.
	 * @param destDir
	 *            Destination directroy to save generated java source codes in
	 *            it.
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws TemplateException
	 * @throws TransformerException
	 */
	public Generator(String configXML, String destDir) throws SAXException, IOException, ParserConfigurationException, TemplateException, TransformerException {
		// Start generating
		logger.info("Hibergui generator started.");
		// Create ConfigReader 
		ConfigReader cr = new ConfigReader(configXML);
		// Gets list of location of XML documents
		ArrayList<String> xmlDocuments = cr.getMappingResources();
		logger.config("Configurations readed from file: \"" + new File(configXML).getAbsolutePath() + "\"");
		// Initializing Freemarker
		Configuration cfg = new Configuration();
		cfg.setClassForTemplateLoading(HiberGUI.class, TEMPLATES_FOLDER);
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		// Get destination directory
		destDir = new File(destDir).getAbsolutePath();
		for (String xml : xmlDocuments){
			// Check if XML document valid and read the contents of it
			MappingReader mr = new MappingReader(xml);
			// Get source file
			File source = new File(xml);
			// Get destination file and create directories if necessary
			String targetFileName = destDir + File.separatorChar + mr.getPackageName(true);
			if (new File(targetFileName).mkdirs()) {
				logger.info("Directories created: \"" + new File(targetFileName).getAbsolutePath() + "\"");
			}
			targetFileName = targetFileName + File.separatorChar + mr.getTargetClassName() + ".java";
			File target = new File(targetFileName);
			// Logging
			logger.info("Start generating from mapping XML: \"" + source.getAbsolutePath() + "\"");
			// Create DOM
			Map root = new HashMap(); 
			root.put("doc", mr.getRootNode());
			// Pass the actual time and date to freemarker via data-model
			root.put("generatingDate", Calendar.getInstance().getTime());
			// Get the template
			Template template = cfg.getTemplate(TEMPLATE_FILENAME);
			// Merging template with data model
			Writer out = new OutputStreamWriter(new FileOutputStream(target), "UTF-8");
			template.process(root, out);
			out.flush();
			// Logging
			logger.info("Successfully finished generating from mapping XML. Source file created: \"" + target.getAbsolutePath() + "\"");
		}
		// Generating finished successfully
		logger.info("HiberGUI finished successfully.");
	}
	
	public Generator(String configXML) throws SAXException, IOException, ParserConfigurationException, TemplateException, TransformerException {
		this(configXML, DEFAULT_DESTDIR);
	}
	
	public static void main(String args[]) throws SAXException, IOException, ParserConfigurationException, TemplateException, TransformerException{
		logger.config("HiberGUI started by java command.");
		if (args.length > 2 || args.length < 1){
			logger.severe(String.format("Usage: %s <configuration xml file> [<destination directory>]", Generator.class.getName()));
			if (args.length > 2) {
				logger.severe("Too much parameters.");
			} else {
				logger.severe("Unspecified configuration XML. Set it as first parameter of Generator!");
			}
			System.exit(1);
		}
		if (args.length == 2) {
			new Generator(args[0], args[1]);
		} else {
			new Generator(args[0]);
		}
	}
	
	/**
	 * Gets actual logger of generator.
	 * 
	 * @return Logger which is logging informations under the process of generating.
	 */
	public static Logger getLogger(){
		return logger;
	}
}
