/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.tools.codegen;

import nuts.core.dao.AbstractModelMetaData;
import nuts.core.dao.sql.criteria.SqlQueryParameter;
import nuts.core.lang.Arrays;
import nuts.core.lang.Classes;
import nuts.core.lang.Strings;
import nuts.core.tool.AbstractCommandTool;
import nuts.exts.ibatis.IBatisModelDAO;
import nuts.tools.codegen.bean.Model;
import nuts.tools.codegen.bean.Module;

import java.util.Map;

import org.apache.commons.cli.CommandLine;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * model source generator
 */
public class IBatisModelGenerator extends ModelGenerator {
	/**
	 * Main class for ModelGenerator
	 */
	public static class Main extends AbstractCodeGenerator.Main {
		/**
		 * @param args arguments
		 */
		public static void main(String[] args) {
			Main cgm = new Main();
			
			AbstractCodeGenerator cg = new IBatisModelGenerator();

			cgm.execute(cg, args);
		}

		@Override
		protected void addCommandLineOptions() throws Exception {
			super.addCommandLineOptions();
			
			addCommandLineOption("t", "dbtype", "Database type (e.g: oracle)");
		}

		@Override
		protected void getCommandLineOptions(CommandLine cl) throws Exception {
			super.getCommandLineOptions(cl);
			
			if (cl.hasOption("t")) {
				setParameter("dbtype", cl.getOptionValue("t").trim());
			}
			else {
				errorRequired(options, "dbtype");
			}
		}

	}

	//---------------------------------------------------------------------------------------
	// properties
	//---------------------------------------------------------------------------------------
	protected String[] dbtypes;
	protected Template tplModelSqlmapXml;
	
	/**
	 * @param dbtype the database to set
	 */
	public void setDbtype(String dbtype) {
		if (dbtype != null) {
			dbtype = dbtype.toLowerCase();
			if ("all".equals(dbtype)) {
				dbtypes = DBTYPE_ALL;
			}
			else {
				dbtypes = Strings.split(dbtype, ", ");
			}
		}
	}

	protected final static String[] DBTYPE_ALL = DDLGenerator.DBTYPE_ALL;

	@Override
	protected void checkParameters() throws Exception {
		super.checkParameters();
		
		AbstractCommandTool.checkRequired(dbtypes, "dbtype");
		for (String t : dbtypes) {
			if (!Arrays.contains(DBTYPE_ALL, t)) {
				throw new IllegalArgumentException("Illegal dbtype [" + t 
					+ "]: must be " + Strings.join(DBTYPE_ALL, ", "));
			}
		}
	}

	@Override
	protected void loadTemplates(Configuration cfg) throws Exception {
		loadTemplates(cfg, "ibatis");
	}
	
	protected void loadSqlmapTemplate(String dbtype) throws Exception {
		tplModelSqlmapXml = loadTemplate(ftlConfig, "ibatis/" + dbtype, "Model-sqlmap.xml.ftl");
	}

	@SuppressWarnings("rawtypes")
	protected Class getBaseModelDAOClass() {
		return IBatisModelDAO.class;
	}
	
	@SuppressWarnings("rawtypes")
	protected Class getBaseExampleClass() {
		return SqlQueryParameter.class;
	}
	
	@SuppressWarnings("rawtypes")
	protected Class getBaseMetaDataClass() {
		return AbstractModelMetaData.class;
	}
	
	protected void processModelDao(Module module, Model model) throws Exception {
		super.processModelDao(module, model);
		processSqlMap(module, model);
	}

	protected void processSqlMap(Module module, Model model) throws Exception {
		for (String t : dbtypes) {
			loadSqlmapTemplate(t);
			Map<String, Object> wrapper = getWrapper(module, model);
			wrapper.put("dbtype", t);
			processTpl(Classes.getPackageName(model.getModelSqlmapClass())
				+ '.' + t, 
				model.getName() + "-sqlmap.xml", 
				wrapper, tplModelSqlmapXml);
		}
	}
}
