package jp.co.headwaters.webappos;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContextEvent;

import jp.co.headwaters.webappos.cache.ActionCache;
import jp.co.headwaters.webappos.cache.ForeignKeyCache;
import jp.co.headwaters.webappos.cache.bean.ActionBean;
import jp.co.headwaters.webappos.cache.bean.BindBean;
import jp.co.headwaters.webappos.cache.bean.CaseBean;
import jp.co.headwaters.webappos.cache.bean.ConditionBean;
import jp.co.headwaters.webappos.cache.bean.ExecuteBean;
import jp.co.headwaters.webappos.cache.bean.FunctionBean;
import jp.co.headwaters.webappos.cache.bean.ResultBean;
import jp.co.headwaters.webappos.common.AppConstants;
import jp.co.headwaters.webappos.common.WebAppOSUtils;
import jp.co.headwaters.webappos.common.enumation.CrudEnum;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.HTMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class WebAppOSGenerator {

	private static final Log logger = LogFactory.getLog(WebAppOSGenerator.class);

	/** アプリケーションAction定義を保持するキャッシュ */
	private ActionCache _actionCache;

	/** foreign key情報を保持するキャッシュ */
	private ForeignKeyCache _foreignKeyCache;

	/** コンテキスト状態変更のイベント */
	private ServletContextEvent _event;

	public void generate(ServletContextEvent event) {
		logger.debug("================= generate start ================= ");

		this._event = event;

		// --------------------------------------------------------------------
		// foreign key情報をキャッシュする
		// --------------------------------------------------------------------
		getForeignKeyInfo();

		// --------------------------------------------------------------------
		// action情報をキャッシュする
		// --------------------------------------------------------------------
		// action定義をhtml配下のディレクトリ構成を元に生成する
		_actionCache = ActionCache.getInstance();
		_actionCache.refresh();
		createActionInfo(new File(AppConstants.HTML_BASE_PATH), null);

		// --------------------------------------------------------------------
		// jspファイルの出力および、実行情報をキャッシュする
		// --------------------------------------------------------------------
		outputJspFile();

		// --------------------------------------------------------------------
		// struts2設定ファイルを出力する
		// --------------------------------------------------------------------
		outputStrutsConfig();

		// --------------------------------------------------------------------
		// MyBatis設定ファイルを出力します
		// --------------------------------------------------------------------
//		outputMapperConfig();

		logger.debug("================= generate  end  ================= ");
	}

	private void getForeignKeyInfo(){
		// JDBC経由でFK情報を取得し、キャッシュする
		Connection conn = null;
		try {
			_foreignKeyCache = ForeignKeyCache.getInstance();

			// TODO:プロパティに設定する
			Class.forName("org.postgresql.Driver");
			conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/testdb", "postgres", "postgres");

			DatabaseMetaData meta = conn.getMetaData();
			String types[] = { "TABLE" };
			ResultSet result = meta.getTables(null, null, "%", types);
			while (result.next()) {
				String tableName = result.getString("TABLE_NAME");
				System.out.println("--------- " + tableName + " ---------");

				// 自分が親の子を保持
				ResultSet exportResult = meta.getExportedKeys(null, "public", tableName);
				while (exportResult.next()) {
					if (exportResult.getString("pktable_name") == null){
						continue;
					}
					_foreignKeyCache.addExportTable(exportResult.getString("pktable_name"), exportResult.getString("fktable_name"));
//					System.out.println("getExportedKeys------------------------");
//					System.out.println("pktable_cat:" + exportResult.getString("pktable_cat"));
//					System.out.println("pktable_schem:" + exportResult.getString("pktable_schem"));
//					System.out.println("pktable_name:" + exportResult.getString("pktable_name"));
//					System.out.println("pkcolumn_name:" + exportResult.getString("pkcolumn_name"));
//					System.out.println("fktable_cat:" + exportResult.getString("fktable_cat"));
//					System.out.println("fktable_schem:" + exportResult.getString("fktable_schem"));
//					System.out.println("fktable_name:" + exportResult.getString("fktable_name"));
//					System.out.println("fkcolumn_name:" + exportResult.getString("fkcolumn_name"));
//					System.out.println("fk_name:" + exportResult.getString("fk_name"));
				}

				// 自分が子の親を保持
				ResultSet importeResult = meta.getImportedKeys(null, "public", tableName);
				while (importeResult.next()) {
					if (importeResult.getString("fktable_name") == null){
						continue;
					}
					_foreignKeyCache.addImportTable(importeResult.getString("fktable_name"), importeResult.getString("pktable_name"));
//					System.out.println("getImportedKeys------------------------");
//					System.out.println("pktable_cat:" + importeResult.getString("pktable_cat"));
//					System.out.println("pktable_schem:" + importeResult.getString("pktable_schem"));
//					System.out.println("pktable_name:" + importeResult.getString("pktable_name"));
//					System.out.println("pkcolumn_name:" + importeResult.getString("pkcolumn_name"));
//					System.out.println("fktable_cat:" + importeResult.getString("fktable_cat"));
//					System.out.println("fktable_schem:" + importeResult.getString("fktable_schem"));
//					System.out.println("fktable_name:" + importeResult.getString("fktable_name"));
//					System.out.println("fkcolumn_name:" + importeResult.getString("fkcolumn_name"));
//					System.out.println("fk_name:" + importeResult.getString("fk_name"));
				}
			}
		} catch (Exception e) {
			// TODO ログはく
			e.printStackTrace();
			return;
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// ignore
				}
			}
		}
	}

	private void createActionInfo(File dir, String parent) {
		File[] files = dir.listFiles();
		if (files == null) {
			return;
		}

		String actionName = null;
		String htmlPath = null;
		for (File file : files) {
			if (file.isDirectory()) {
				// svn管理フォルダの場合、除外する
				if (".svn".equalsIgnoreCase(file.getName())) {
					continue;
				}

				// サブディレクトリの場合、ディレクトリ名を結合した文字列をAction名とする(CamelCase)
				if (parent != null){
					actionName = parent + StringUtils.capitalize(file.getName());
				}else{
					actionName = file.getName();
				}

				// htmlファイルのhtmlディレクトリからの相対パスを取得する
				htmlPath = file.getAbsolutePath().replace(AppConstants.HTML_BASE_PATH, "");
				_actionCache.getActionMap().put(actionName, new ActionBean(actionName, htmlPath));

				// 再起的に処理する
				createActionInfo(file, actionName);
			}
		}
	}

	private void outputJspFile(){

		// --------------------------------------------------------------------
		// jsp格納ディレクトリを生成する
		// --------------------------------------------------------------------
		createJspDirectory();

		// --------------------------------------------------------------------
		// ディレクトリ、ファイル別に処理を行う
		// --------------------------------------------------------------------
		SAXReader reader = new SAXReader();
		String jsprRlativeFilePath = null;
		String jspFilePath = null;
		String jspWorkFilePath = null;
		for (ActionBean actionBean : _actionCache.getActionMap().values()) {
			// html格納ディレクトリ内のhtmlファイルを処理対象とする
			String dir = AppConstants.HTML_BASE_PATH + actionBean.getHtmlPath();
			File[] htmlFiles = new File(dir).listFiles(WebAppOSUtils.getHtmlFileFilter());
			for (File file : htmlFiles) {
				try {
					// --------------------------------------------------------------------
					// html→jspファイル（ワークファイル）
					// --------------------------------------------------------------------
					jsprRlativeFilePath = actionBean.getHtmlPath() +
										System.getProperty("file.separator") +
										WebAppOSUtils.convertExtensionHtmlToJsp(file.getName());
					jspFilePath = AppConstants.JSP_BASE_PATH + jsprRlativeFilePath;
					jspWorkFilePath = AppConstants.JSP_WORK_BASE_PATH + jsprRlativeFilePath;

					// htmlファイルをコピーし、jspファイルを生成する
					WebAppOSUtils.copyFile(file, jspWorkFilePath);
					logger.debug("-----------------" + jspWorkFilePath + " START -----------------");

					// --------------------------------------------------------------------
					// アクション別実行情報の初期化
					// --------------------------------------------------------------------
					// form識別子-実行情報
					Map<String, ExecuteBean> submitExecuteMap = actionBean.getSubmitExecuteMap();
					if (submitExecuteMap == null) {
						submitExecuteMap = new HashMap<String, ExecuteBean>();
						actionBean.setSubmitExecuteMap(submitExecuteMap);
					}
					// 画面ロード-実行情報
					Map<String, ExecuteBean> loadExecuteMap = actionBean.getLoadExecuteMap();
					if (loadExecuteMap == null) {
						loadExecuteMap = new HashMap<String, ExecuteBean>();
						actionBean.setLoadExecuteMap(loadExecuteMap);
					}

					// --------------------------------------------------------------------
					// jsp(html)解析
					// jspを解析し、実行情報等を取得する
					// また、必要な実行に要素を追加する
					// --------------------------------------------------------------------
					// jspファイルを読み込み
					Document document = reader.read(jspWorkFilePath);
					document.getRootElement().addNamespace("s", "/struts-tags");

					// --------------------------------------------------------------------
					// 画面ロード時の実行機能情報取得
					// --------------------------------------------------------------------
					// 実行情報を保持するBeanを初期化する
					ExecuteBean loadExecuteInfo = new ExecuteBean();
					loadExecuteInfo.setResult(new ResultBean());
					loadExecuteInfo.setFunctionList(new ArrayList<FunctionBean>());
					// data-load属性を取得
					List loadNodes = document.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_LOAD);
					for (Object loadNode : loadNodes){
						if (loadNode instanceof Attribute){
							// --------------------------------------------------------------------
							// 実行情報を保持するBeanを初期化する
							// --------------------------------------------------------------------
							Attribute loadAttr = (Attribute)loadNode;
							Element element = loadAttr.getParent();
							String funcInfo = loadAttr.getValue();
							// div要素配下の要素から機能情報およびステートメント情報を抽出し、キャッシュする
							FunctionBean function = createFunctionInfo(funcInfo, element);
							if (function != null) {
								loadExecuteInfo.getFunctionList().add(function);
							}
						}
					}
					loadExecuteMap.put(System.getProperty("file.separator") + AppConstants.JSP_DIR + jsprRlativeFilePath, loadExecuteInfo);

					// --------------------------------------------------------------------
					// Path属性の差し替え
					// href属性、src属性、objectタグdata属性、paramタグvalue属性
					// --------------------------------------------------------------------
					for (Object node : document.selectNodes("descendant::node()/@href")) {
						convertPath((Attribute)node);
					}

					for (Object node : document.selectNodes("descendant::node()/@src")) {
						convertPath((Attribute)node);
					}

					for (Object node : document.selectNodes("descendant::object/@data")) {
						convertPath((Attribute)node);
					}

					for (Object node : document.selectNodes("descendant::object/child::param/@value")) {
						convertPath((Attribute)node);
					}

					// --------------------------------------------------------------------
					// data-const属性の差し替え
					// --------------------------------------------------------------------
					// TODO:定数使用する時にもう一度考える。。
					// Element配下のdata-const属性の内容を取得する
//					List constNodes = document.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_CONST);
//					for (Object constNode : constNodes) {
//						Attribute constAttr = (Attribute)constNode;
//						Element parentElement = constAttr.getParent();
//						// data-const属性を削除する
//						parentElement.remove(constAttr);
//						try {
//							ConstantBean constBean = mapper.readValue(constAttr.getValue(), new TypeReference<ConstantBean>(){});
//							String attrName = constBean.getTarget();
//							String attrValue = null;
//							String category = constBean.getCategory();
//							String key = constBean.getKey();
//							String format = constBean.getFormat();
//
//							if (StringUtils.isEmpty(attrName)) {
//								if (StringUtils.isEmpty(key)) {
//									// TODO:Keyが未指定の場合は、リストで取得し、iteratorで出力。
//								} else {
//									// Keyが設定されている場合、Textに設定
//									if (!StringUtils.isEmpty(category)){
//										parentElement.setText("＜s:property value=”%{@jp.co.headwaters.webappos.cache.SystemConstantCache@getSystemConstant2('" + category + "','" + key + "')}”/＞");
//									} else {
//										parentElement.setText("＜s:property value=”%{@jp.co.headwaters.webappos.cache.SystemConstantCache@getSystemConstant2('" + key + "')}”/＞");
//									}
//								}
//							} else {
//								if (StringUtils.isEmpty(format)) {
//									format = "{0}";
//								}
//								attrValue = MessageFormat.format(format, "＜s:property value=”%{@jp.co.headwaters.webappos.cache.SystemConstantCache@getSystemConstant2('" + key + "')}”/＞");
//								parentElement.addAttribute(attrName, attrValue);
//							}
//						} catch (Exception e) {
//							// TODO:例外処理
//							e.printStackTrace();
//						}
//					}

					// --------------------------------------------------------------------
					// form別処理
					// --------------------------------------------------------------------
					List nodes = document.selectNodes("//form");
					String formId = null;
					for(Iterator i = nodes.iterator(); i.hasNext();) {
						// form要素を取得する
						Element formElement = (Element)i.next();

						// 実行情報を保持するBeanを初期化する
						ExecuteBean submitExecuteInfo = new ExecuteBean();
						submitExecuteInfo.setResult(new ResultBean());
						submitExecuteInfo.setFunctionList(new ArrayList<FunctionBean>());

						// --------------------------------------------------------------------
						// form識別子要素を追加する
						// --------------------------------------------------------------------
						// form識別子を生成し、formの子要素として追加する
						// TODO:バリデーション
						formId = String.valueOf((file.getAbsolutePath() + formElement.attributeValue("id")).hashCode());
						formElement.addElement("input")
								.addAttribute("type", "hidden")
								.addAttribute("name", AppConstants.FORM_ID_NAME)
								.addAttribute("value", formId);
						// form識別子毎に実行情報を保持する
						// submit時に実行機能を識別する為に使用する
						submitExecuteMap.put(formId, submitExecuteInfo);

						// --------------------------------------------------------------------
						// resultタグ情報生成
						// --------------------------------------------------------------------
						// formタグの属性を取得する
						String actionValue = WebAppOSUtils.convertExtensionHtmlToJsp(formElement.attributeValue("action"));
						logger.debug("form action:" + actionValue);
						if (StringUtils.isEmpty(actionValue)){
							continue;
						}
						actionValue  = actionValue.replace("/", System.getProperty("file.separator"));
						String jspFileName;
						if (actionValue.startsWith("..")) {
							// カレントディレクトリ以外
							if (actionValue.length() <= 3){
								// TODO:WARNログを出力する
								continue;
							}
							jspFileName = AppConstants.JSP_DIR + actionValue.substring(3);
						} else if (actionValue.startsWith(".")) {
							// カレントディレクトリ
							jspFileName = AppConstants.JSP_DIR + actionBean.getName() + actionValue.substring(1);
						} else {
							// カレントディレクトリ
							jspFileName = AppConstants.JSP_DIR + actionBean.getName() + System.getProperty("file.separator") + actionValue;
						}

						// result情報を生成し、実行情報に保持する
						ResultBean result = submitExecuteInfo.getResult();
						result.setName("result" + submitExecuteMap.size());
						result.setValue(System.getProperty("file.separator") + jspFileName);

						// --------------------------------------------------------------------
						// action属性を設定する
						// --------------------------------------------------------------------
						formElement.addAttribute("action", actionBean.getName());

						// --------------------------------------------------------------------
						// 機能情報の生成
						// data-func属性の抽出、ステートメント情報の取得
						// --------------------------------------------------------------------
						Attribute funcAttr = (Attribute)formElement.attribute(AppConstants.DATA_ATTRIBUTE_NAME_FUNC);
						String funcInfo = null;
						if (funcAttr != null) {
							funcInfo = funcAttr.getValue();
							// formの属性から機能情報を取得する
							FunctionBean function = createFunctionInfo(funcInfo, formElement);
							deleteDataAttribute(formElement);
							if (function != null) {
								submitExecuteInfo.getFunctionList().add(function);
							}
							formElement.remove(funcAttr);
						} else {
							// formの属性に未設定の場合、form配下のdiv要素の属性から機能情報を取得する
							List list = formElement.selectNodes("./div");
							for (Object obj : list) {
								Element divElement = (Element)obj;
								funcAttr = (Attribute)divElement.attribute(AppConstants.DATA_ATTRIBUTE_NAME_FUNC);
								if (funcAttr != null){
									funcInfo = funcAttr.getValue();
									// div要素配下の要素から機能情報およびステートメント情報を抽出し、キャッシュする
									FunctionBean function = createFunctionInfo(funcInfo, divElement);
									deleteDataAttribute(divElement);
									if (function != null) {
										submitExecuteInfo.getFunctionList().add(function);
									}
									divElement.remove(funcAttr);
								}
							}
						}
					}

					// --------------------------------------------------------------------
					// 画面ロード時のdata属性を削除する
					// --------------------------------------------------------------------
					for (Object loadNode : loadNodes){
						if (loadNode instanceof Attribute){
							Attribute loadAttr = (Attribute)loadNode;
							Element element = loadAttr.getParent();
							deleteDataAttribute(element);
							element.remove(loadAttr);
						}
					}

					// --------------------------------------------------------------------
					// jspファイルを書き換える
					// TODO:インデント、整形
					// --------------------------------------------------------------------
					OutputFormat outputFormat = new OutputFormat(null, false, "UTF-8");
					// XML文書宣言を省略する
					outputFormat.setSuppressDeclaration(true);
					outputFormat.setExpandEmptyElements(true);
					HTMLWriter xw = null;
					try {
						document.setDocType(null);
						xw = new HTMLWriter(new FileWriter(jspWorkFilePath), outputFormat);
						xw.write(document);
						xw.flush();
					} catch (IOException e) {
						// TODO:WARNログを出力する
						e.printStackTrace();
					}finally{
						if (xw != null) {
							try {
								xw.close();
							} catch (IOException e) {
								// ignore
							}
						}
			        }

					// --------------------------------------------------------------------
					// jspディレクティブを挿入する
					// --------------------------------------------------------------------
					writeJspDirective(jspWorkFilePath, jspFilePath);

				} catch (DocumentException e) {
					// TODO:HTML解析エラー　WARNログを出力する
					e.printStackTrace();
				}
			}
		}

		// --------------------------------------------------------------------
		// ワークファイルを削除する
		// --------------------------------------------------------------------
		WebAppOSUtils.deleteFile(new File(AppConstants.JSP_WORK_BASE_PATH));
	}

	private void createJspDirectory() {
		// jspディレクトリ配下のディレクトリ、ファイルを全て削除する
		WebAppOSUtils.deleteFile(new File(AppConstants.JSP_BASE_PATH));

		// Action情報を元にjspファイル格納ディレクトリを生成する
		for (ActionBean actionBean : _actionCache.getActionMap().values()) {
			File file = new File(AppConstants.JSP_BASE_PATH + actionBean.getHtmlPath());
			file.mkdirs();
		}

		// ワークファイル用
		// jspディレクトリ配下のディレクトリ、ファイルを全て削除する
		WebAppOSUtils.deleteFile(new File(AppConstants.JSP_WORK_BASE_PATH));

		// Action情報を元にjspファイル格納ディレクトリを生成する
		for (ActionBean actionBean : _actionCache.getActionMap().values()) {
			File file = new File(AppConstants.JSP_WORK_BASE_PATH + actionBean.getHtmlPath());
			file.mkdirs();
		}
	}

	private void convertDataCondAttribute(FunctionBean function, Element element)
			throws JsonParseException, JsonMappingException, IOException {
		ObjectMapper mapper = new ObjectMapper();
		// Element配下のdata-cond属性の内容を取得する
		List condNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_COND);
		for (Object condNode : condNodes) {
			Attribute condAttr = (Attribute)condNode;
			Element parentElement = condAttr.getParent();
			String value = condAttr.getValue();
			ConditionBean cond = mapper.readValue(value, ConditionBean.class);
			function.getCondMap().put(cond.getTableName() + cond.getColumnName(), cond.getOperator());
			String paramName = null;
			if (!StringUtils.isEmpty(cond.getTableName())) {
				paramName = function.getResult() + "__cond__" + cond.getTableName() + "__" + cond.getColumnName() + "__";
			} else {
				paramName = function.getResult() + "__cond__" + function.getTarget() + "__" + cond.getColumnName() + "__";
			}
			if (!StringUtils.isEmpty(cond.getOption())) {
				paramName += cond.getOption();
			}

			// name属性を追加する
			parentElement.addAttribute("name", paramName);
			// value属性を追加する
			if (StringUtils.isEmpty(parentElement.attributeValue("value"))) {
				parentElement.addAttribute("value", "＜s:property value=”resultMap.request." + paramName + "”/＞");
			}
		}
	}

	private void convertDataBindAttribute(FunctionBean function, Element element)
			throws JsonParseException, JsonMappingException, IOException {
		ObjectMapper mapper = new ObjectMapper();
		// Element配下のdata-bind属性の内容を取得する
		List bindNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_BIND);
		for (Object bindNode : bindNodes) {
			Attribute bindAttr = (Attribute)bindNode;
			Element parentElement = bindAttr.getParent();
			String value = bindAttr.getValue();
			List<BindBean> bindList = mapper.readValue(value, new TypeReference<List<BindBean>>(){});

			for (BindBean bind : bindList) {
				String target = bind.getTarget();
				String attrValue = null;
				String format = bind.getFormat();
				boolean isEscape = Boolean.valueOf(bind.getEscape());
				String escapeStr = "";
				if (!isEscape){
					escapeStr = " escape=”false”";
				}

				String name = function.getResult() + "__col__" + bind.getColumnName();
				if ("input".equals(parentElement.getName())) {
					// name属性を追加する
					if (StringUtils.isEmpty(parentElement.attributeValue("name"))) {
						parentElement.addAttribute("name", name);
					}
				}

				if (!StringUtils.isEmpty(target)) {
					if ("text".equalsIgnoreCase(target)) {
						if (CrudEnum.CRUD_SELECT_BY_EXAMPLE.getType().equals(function.getMethod())
								|| CrudEnum.CRUD_SELECT_ALL_BY_EXAMPLE.getType().equals(function.getMethod())) {
							// Textに設定（Listの場合）
							parentElement.setText("＜s:property value=”" + bind.getColumnName() + "”" + escapeStr + "/＞");
						} else {
							parentElement.setText("＜s:property value=”resultMap." + function.getResult() + "." + bind.getColumnName() + "”" + escapeStr + "/＞");
						}
					} else {
						if (StringUtils.isEmpty(format)) {
							format = "{0}";
						}

						if (CrudEnum.CRUD_SELECT_BY_EXAMPLE.getType().equals(function.getMethod()) || CrudEnum.CRUD_SELECT_ALL_BY_EXAMPLE.getType().equals(function.getMethod())) {
							// List
							attrValue = MessageFormat.format(format, "＜s:property value=”" + bind.getColumnName() + "”" + escapeStr + "/＞");
						} else if (CrudEnum.CRUD_SELECT_BY_PRIMARYKEY.getType().equals(function.getMethod())) {
							//  単一
							attrValue = MessageFormat.format(format, "＜s:property value=”resultMap." + function.getResult() + "." + bind.getColumnName() + "”" + escapeStr + "/＞");
						} else {
							attrValue = MessageFormat.format(format, "＜s:property value=”resultMap.request." + name + "”" + escapeStr + "/＞");
						}
						String oldAttr = parentElement.attributeValue(target);
						if (oldAttr == null || !oldAttr.startsWith("＜s:property")) {
							parentElement.addAttribute(target, attrValue);
						}
					}
				}
			}
		}
	}

	private void convertDataSortAttribute(FunctionBean function, Element element)
			throws JsonParseException, JsonMappingException, IOException {
		ObjectMapper mapper = new ObjectMapper();
		// Element配下のdata-sort属性の内容を取得する
		Node sortNode = element.selectSingleNode("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_SORT);
		if (sortNode != null) {
			Attribute sortAttr = (Attribute)sortNode;
			String value = sortAttr.getValue();

			List<String> sortList = mapper.readValue(value, new TypeReference<List<String>>(){});
			if (sortList != null && sortList.size() > 0) {
				Element sortElement = sortAttr.getParent().addElement("input");
				sortElement.addAttribute("type", "hidden");
				sortElement.addAttribute("name", function.getResult() + "__sort____");
				sortElement.addAttribute("value", StringUtils.join(sortList, ","));
			}
		}
	}

	private void convertDataCaseAttribute(FunctionBean function, Element element)
			throws JsonParseException, JsonMappingException, IOException {
		ObjectMapper mapper = new ObjectMapper();
		// Element配下のdata-case属性を書き換える
		List caseNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_CASE);
		for (Object caseNode : caseNodes) {
			Attribute caseAttr = (Attribute)caseNode;
			Element parentElement = caseAttr.getParent();

			Node ancestorIteratorNode = parentElement.selectSingleNode("ancestor::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_ITERATOR);
			String ognlRoot = "";
			if (ancestorIteratorNode == null) {
				ognlRoot = "resultMap.";
			}

			// data-func属性に指定されたJSONをparseする
			List<CaseBean> caseList = mapper.readValue(caseAttr.getValue(), new TypeReference<List<CaseBean>>(){});

			StringBuilder testValue = new StringBuilder();
			for (int i = 0; i < caseList.size(); i++) {
				CaseBean caseInfo = caseList.get(i);
				if ("size".equals(caseInfo.getType())) {
					testValue.append(ognlRoot);
					testValue.append(caseInfo.getArgList().get(0));
					testValue.append(".size");
					testValue.append(getOperatorString(caseInfo.getArgList().get(1)));
					testValue.append(caseInfo.getArgList().get(2));
				} else if ("compare".equals(caseInfo.getType())) {
					testValue.append(ognlRoot);
					testValue.append(caseInfo.getArgList().get(0));
					testValue.append(getOperatorString(caseInfo.getArgList().get(1)));
					testValue.append(caseInfo.getArgList().get(2));
				} else if ("instanceof".equals(caseInfo.getType())) {
					testValue.append(ognlRoot);
					testValue.append(caseInfo.getArgList().get(0));
					testValue.append(" instanceof ");
					testValue.append(caseInfo.getArgList().get(1));
				} else if ("!instanceof".equals(caseInfo.getType())) {
					testValue.append("!");
					testValue.append(ognlRoot);
					testValue.append(caseInfo.getArgList().get(0));
					testValue.append(" instanceof ");
					testValue.append(caseInfo.getArgList().get(1));
				}
				if (i < caseList.size() - 1) {
					testValue.append(" || ");
				}
			}

			// if要素を生成する
			Element ifElement = DocumentHelper.createElement("s:if");
			ifElement.addAttribute("test",testValue.toString());

			// if要素をdata-case属性が指定されていた要素位置に追加する
			Element grandParentElement = caseAttr.getParent().getParent();
			List elements = grandParentElement.elements();
			elements.add(elements.indexOf(parentElement), ifElement);

			// data-case属性が指定された要素および子孫要素の階層を変更する
			List childList = parentElement.selectNodes(".");
			grandParentElement.remove(parentElement);
			for (Object child : childList){
				Element childElement = (Element)child;
				ifElement.add(childElement);
			}
		}
	}

	private void convertDataIteratorAttribute(FunctionBean function, Element element) {
		// Element配下のdata-iterator属性を書き換える
		List iteratorNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_ITERATOR);
		for (Object iteratorNode : iteratorNodes) {
			Attribute iteratorAttr = (Attribute)iteratorNode;
			Element parentElement = iteratorAttr.getParent();

			// 祖先にdata-iteratorが存在するか確認する（存在した場合、多重ループ）
			Node ancestorIteratorNode = parentElement.selectSingleNode("ancestor::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_ITERATOR);
			String ognlRoot = "";
			if (ancestorIteratorNode == null) {
				ognlRoot = "resultMap.";
			}

			// iterator要素を生成する
			Element iteratorElement = DocumentHelper.createElement("s:iterator");
			iteratorElement.addAttribute("value", "%{" + ognlRoot + iteratorAttr.getValue() + "}");
			iteratorElement.addAttribute("status", "st");

			// iterator要素をdata-iterator属性が指定されていた要素位置に追加する
			Element grandParentElement = iteratorAttr.getParent().getParent();
			List elements = grandParentElement.elements();
			elements.add(elements.indexOf(parentElement), iteratorElement);

			// data-iterator属性が指定された要素および子孫要素の階層を変更する
			List childList = parentElement.selectNodes(".");
			grandParentElement.remove(parentElement);
			for (Object child : childList){
				Element childElement = (Element)child;
				iteratorElement.add(childElement);
			}
		}
	}

	private void deleteDataAttribute(Element element) {
		// data-cond,data-bind,data-sort,data-iterator属性を削除する
		// Element配下のdata-cond属性の内容を取得する
		List condNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_COND);
		for (Object condNode : condNodes) {
			Attribute condAttr = (Attribute)condNode;
			Element parentElement = condAttr.getParent();
			parentElement.remove(condAttr);
		}

		// Element配下のdata-bind属性の内容を取得する
		List bindNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_BIND);
		for (Object bindNode : bindNodes) {
			Attribute bindAttr = (Attribute)bindNode;
			Element parentElement = bindAttr.getParent();
			parentElement.remove(bindAttr);
		}

		// Element配下のdata-sort属性の内容を取得する
		Node sortNode = element.selectSingleNode("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_SORT);
		if (sortNode != null) {
			Attribute sortAttr = (Attribute)sortNode;
			Element parentElement = sortAttr.getParent();
			// data-sort属性を削除する
			parentElement.remove(sortAttr);
		}

		// Element配下のdata-case属性の内容を取得する
		List caseNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_CASE);
		for (Object caseNode : caseNodes) {
			Attribute caseAttr = (Attribute)caseNode;
			Element parentElement = caseAttr.getParent();
			parentElement.remove(caseAttr);
		}

		// Element配下のdata-iterator属性の内容を取得する
		List iteratorNodes = element.selectNodes("descendant::node()/@" + AppConstants.DATA_ATTRIBUTE_NAME_ITERATOR);
		for (Object iteratorNode : iteratorNodes) {
			Attribute iteratorAttr = (Attribute)iteratorNode;
			Element parentElement = iteratorAttr.getParent();
			parentElement.remove(iteratorAttr);
		}
	}

	private FunctionBean createFunctionInfo(String funcInfo, Element element) {
		ObjectMapper mapper = new ObjectMapper();
		FunctionBean function = null;
		try {
			// data-func属性に指定されたJSONをparseする
			function = mapper.readValue(funcInfo, FunctionBean.class);
			if ("func_crud".equals(function.getType())) {
				// CRUDの場合
				function.setCondMap(new HashMap<String, String>());

				convertDataCondAttribute(function, element);

				convertDataBindAttribute(function, element);

				convertDataSortAttribute(function, element);

				convertDataCaseAttribute(function, element);

				convertDataIteratorAttribute(function, element);

			} else if ("func_sendmail".equals(function.getType())) {
				// メール送信の場合
				convertDataBindAttribute(function, element);
			}
		} catch (Exception e) {
			// TODO:WARNログを出力する
			e.printStackTrace();
		}
		return function;
	}

	private void writeJspDirective(String jspWorkFilePath, String jspFilePath) {

		// input
		FileInputStream fsi = null;
		InputStreamReader isr = null;
		BufferedReader br = null;

		// output
		FileOutputStream fos = null;
		OutputStreamWriter osw = null;
		PrintWriter pw = null;
		try {
			fsi = new FileInputStream(jspWorkFilePath);
			isr = new InputStreamReader(fsi, AppConstants.HTML_ENCODING);
			br = new BufferedReader(isr);

			fos = new FileOutputStream(new File(jspFilePath));
			osw = new OutputStreamWriter(fos, AppConstants.HTML_ENCODING);
			pw = new PrintWriter(osw);

			// jspディレクティブを出力する
			pw.println("<%@ page contentType=\"text/html; charset=UTF-8\" pageEncoding=\"" + AppConstants.HTML_ENCODING +"\"%>");
			pw.println("<%@ taglib prefix=\"s\" uri=\"/struts-tags\"%>");
			pw.println("<html>");

			// ワークファイルをそのまま出力する
			String line = null;
			while ((line = br.readLine()) != null) {
				if (line.startsWith("<html")){
					continue;
				}
				pw.println(line.replaceAll("＜", "<").replace("＞", ">").replaceAll("”", "\""));
			}
		} catch (Exception e1) {
			// TODO ログ出力とか
			e1.printStackTrace();
		} finally {
			if (pw != null) {
				pw.close();
			}
			if (osw != null){
				try {
					osw.close();
				} catch (IOException e) {
					// ignore
				}
			}
			if (fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					// ignore
				}
			}
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					// ignore
				}
			}
			if (isr != null){
				try {
					isr.close();
				} catch (IOException e) {
					// ignore
				}
			}
			if (fsi != null){
				try {
					fsi.close();
				} catch (IOException e) {
					// ignore
				}
			}
		}
	}

	private void outputStrutsConfig() {
		SAXReader reader = new SAXReader();
		try {
			File file = new File(AppConstants.CONFIG_FILE_PATH).getAbsoluteFile();
			Document document = reader.read(file);
			Element packageElement = (Element) document.selectSingleNode("//package");

			// package配下の要素を一旦削除する
			Iterator iterator = packageElement.elementIterator();
			while (iterator.hasNext()) {
				Element childElement = (Element) iterator.next();
				packageElement.remove(childElement);
			}

			for (ActionBean actionBean : _actionCache.getActionMap().values()) {
				// actionタグを追加する
				Element actionElement = packageElement.addElement("action");
				actionElement.addAttribute("name", actionBean.getName());
				actionElement.addAttribute("class", AppConstants.GENERIC_ACTION_NAME);

				// default result(success)
				Element defaultResultElement = actionElement.addElement("result");
				defaultResultElement.addAttribute("name", "success");
				defaultResultElement.addText(System.getProperty("file.separator") + AppConstants.JSP_DIR + actionBean.getHtmlPath() + AppConstants.DEFAULT_RESULT_FILE_NAME);

				if (actionBean.getSubmitExecuteMap() != null){
					for (ExecuteBean execInfo: actionBean.getSubmitExecuteMap().values()){
						ResultBean resultInfo = execInfo.getResult();
						// resultタグを追加する
						Element resultElement = actionElement.addElement("result");
						resultElement.addAttribute("name", resultInfo.getName());
						resultElement.addText(resultInfo.getValue());
					}
				}
			}

			OutputFormat outputFormat = new OutputFormat("\t", true, "UTF-8");
			XMLWriter xw = null;
			try {
				xw = new XMLWriter(new FileWriter(file), outputFormat);
				xw.write(document);
				xw.flush();
			} catch (IOException e) {
				// TODO:WARNログを出力する
				e.printStackTrace();
			} finally {
				if (xw != null) {
					try {
						xw.close();
					} catch (IOException e) {
						// ignore
					}
				}
			}
		} catch (DocumentException e) {
			// TODO:WARNログを出力する
			e.printStackTrace();
		}
	}

//	private void outputMapperConfig() {
//		// mapperファイル名
//		String fileName;
//		// ステートメントid生成時に使用するsqlNo。mapper内でユニーク
//		int seqNo = 0;
//		// mybatis-config.xml定義用にmapperファイル名を保持するList
//		List<String> mapperList = new ArrayList<String>();
//
//		// --------------------------------------------------------------------
//		// mapperファイル出力ディレクトリの準備
//		// --------------------------------------------------------------------
//		// mapperディレクトリ配下のファイルを全て削除する
//		File baseFile = new File(AppConstants.MAPPER_BASE_PATH);
//		WebAppOSUtils.deleteFile(baseFile);
//		baseFile.mkdir();
//
//		// --------------------------------------------------------------------
//		// アクション別にmapperファイル出力
//		// --------------------------------------------------------------------
//		for (ActionBean actionBean : _actionCache.getActionMap().values()) {
//			if (actionBean.getSubmitExecuteMap() == null && actionBean.getLoadExecuteMap() == null) {
//				continue;
//			}
//
//			// mapperファイルは、action単位
//			fileName = AppConstants.MAPPER_BASE_PATH + actionBean.getName() + AppConstants.MAPPER_SUFFIX;
//			Document document = DocumentHelper.createDocument();
//
//			// DOCTYPE定義を出力する
//			document.addDocType(AppConstants.MAPPER_DOCTYPE_NAME,
//					AppConstants.MAPPER_DOCTYPE_PUBLICID,
//					AppConstants.MAPPER_DOCTYPE_SYSTEMID);
//
//			Element mapperElement = document.addElement("mapper");
//			mapperElement.addAttribute("namespace", actionBean.getName());
//
//			// seqNoをクリアする
//			seqNo = 0;
//
//			// --------------------------------------------------------------------
//			// xml生成
//			// --------------------------------------------------------------------
//			for (ExecuteBean execInfo : actionBean.getSubmitExecuteMap().values()) {
//				for (FunctionBean function : execInfo.getFunctionList()) {
//					outputStatment(mapperElement, function, ++seqNo);
//				}
//			}
//
//			for (ExecuteBean execInfo : actionBean.getLoadExecuteMap().values()) {
//				for (FunctionBean function : execInfo.getFunctionList()) {
//					outputStatment(mapperElement, function, ++seqNo);
//				}
//			}
//
//			// --------------------------------------------------------------------
//			// xml出力
//			// --------------------------------------------------------------------
//			OutputFormat outputFormat = new OutputFormat("\t", true, "UTF-8");
//			XMLWriter xw = null;
//			File file = new File(fileName);
//			try {
//				xw = new XMLWriter(new FileWriter(file), outputFormat);
//				xw.write(document);
//				xw.flush();
//			} catch (IOException e) {
//				// TODO:WARNログを出力する
//				e.printStackTrace();
//			} finally {
//				if (xw != null){
//					try {
//						xw.close();
//					} catch (IOException e) {
//						// ignore
//					}
//				}
//			}
//
//			// mybatis-config.xml定義用にmapperファイル名を保持しておく
//			mapperList.add(file.getName());
//		}
//
//		// --------------------------------------------------------------------
//		// mybatis-config.xml更新
//		// --------------------------------------------------------------------
//		outputMybatisConfig(mapperList);
//	}

//	private void outputStatment(Element mapperElement, FunctionBean function, Integer seqNo){
//		String mapperName;
//		StatementBean statementBean = function.getStatement();
//		if (FunctionEnum.FUNCTION_CRUD.getFunctionName().equals(function.getType())) {
//			mapperName = AppConstants.STATEMENT_PREFIX + seqNo;
//			function.setMapperName(mapperName);
//
//			// curd命令
//			if (CrudEnum.CRUD_SELECT_ONE.getType().equals(function.getMethod())) {
//				// select要素
//				Element selectElement = mapperElement.addElement("select");
//				selectElement.addAttribute("id", mapperName);
//				selectElement.addAttribute("parameterType", "hashmap");
//				selectElement.addAttribute("resultType", "hashmap");
//
//				// ステートメント生成
//				StringBuilder statment = new StringBuilder();
//				// select句
//				statment.append("select ");
//				statment.append(createSelectClause(statementBean.getBindList()));
//				// from句
//				statment.append(" from " + statementBean.getTableName());
//				selectElement.addText(statment.toString());
//				// where句
//				createSelectWhereClause(selectElement, statementBean.getConditionList(), true);
//				// orderBy句
//				createSortClause(selectElement, statementBean.getSortList());
//			} else if (CrudEnum.CRUD_SELECT_LIST.getType().equals(function.getMethod())) {
//				// select要素
//				Element selectElement = mapperElement.addElement("select");
//				selectElement.addAttribute("id", mapperName);
//				selectElement.addAttribute("parameterType", "hashmap");
//				selectElement.addAttribute("resultType", "hashmap");
//
//				StringBuilder statment = new StringBuilder();
//				// select句
//				statment.append("select ");
//				statment.append(createSelectClause(statementBean.getBindList()));
//				// from句
//				statment.append(" from " + statementBean.getTableName());
//				selectElement.addText(statment.toString());
//				// where句
//				createSelectWhereClause(selectElement, statementBean.getConditionList(), false);
//				// orderBy句
//				createSortClause(selectElement, statementBean.getSortList());
//			} else if (CrudEnum.CRUD_INSERT.getType().equals(function.getMethod())) {
//				// insert要素
//				Element insertElement = mapperElement.addElement("insert");
//				insertElement.addAttribute("id", mapperName);
//				insertElement.addAttribute("parameterType", "hashmap");
//
//				// ステートメント生成
//				StringBuilder statment = new StringBuilder();
//				statment.append("insert into ");
//				statment.append(statementBean.getTableName());
//				statment.append(" (");
//				// insert col
//				statment.append(createInsertColClause(statementBean.getBindList()));
//				statment.append(") values (");
//				// insert value
//				statment.append(createInsertValueClause(statementBean.getBindList()));
//				statment.append(")");
//				insertElement.addText(statment.toString());
//			} else if (CrudEnum.CRUD_UPDATE.getType().equals(function.getMethod())) {
//				// update要素
//				Element updateElement = mapperElement.addElement("update");
//				updateElement.addAttribute("id", mapperName);
//				updateElement.addAttribute("parameterType", "hashmap");
//
//				StringBuilder statment = new StringBuilder();
//				statment.append("update ");
//				statment.append(statementBean.getTableName());
//				statment.append(" set ");
//				updateElement.addText(statment.toString());
//				// update col
//				createUpdateColClause(updateElement, statementBean.getBindList());
//				statment = new StringBuilder();
//				// update condition
//				statment.append(" where ");
//				statment.append(createDeleteWhereClause(statementBean.getConditionList()));
//				updateElement.addText(statment.toString());
//			} else if (CrudEnum.CRUD_DELETE.getType().equals(function.getMethod())) {
//				// delete要素
//				Element deleteElement = mapperElement.addElement("delete");
//				deleteElement.addAttribute("id", mapperName);
//				deleteElement.addAttribute("parameterType", "hashmap");
//
//				// ステートメント生成
//				StringBuilder statment = new StringBuilder();
//				statment.append("delete from ");
//				statment.append(statementBean.getTableName());
//				statment.append(" where ");
//				statment.append(createDeleteWhereClause(statementBean.getConditionList()));
//				deleteElement.addText(statment.toString());
//			}
//		}
//	}

	private String createSelectClause(List<BindBean> bindList) {
		if (bindList == null) {
			return "";
		}

		List<String> colList = new ArrayList<String>();
		StringBuilder statment = new StringBuilder();
		for (BindBean bind : bindList){
			if (!colList.contains(bind.getColumnName())) {
				colList.add(bind.getColumnName());
			}
		}
		for (int i = 0; i < colList.size(); i++) {
			statment.append(colList.get(i));
			if (i < colList.size() - 1) {
				statment.append(",");
			}
		}
		return statment.toString();
	}

	private void createSelectWhereClause(Element element, List<ConditionBean> condList, boolean isRequired) {
		if (condList == null) {
			return;
		}

		Element trimElement = null;
		if (!isRequired) {
			trimElement = element.addElement("trim");
			trimElement.addAttribute("prefix", "where");
			trimElement.addAttribute("prefixOverrides", "and |or ");
		} else {
			if (condList.size() > 0) {
				element.addText(" where ");
			}
		}

		String condName;
		for (int i = 0; i < condList.size(); i++) {
			ConditionBean cond = condList.get(i);

			// bind用の変数
			condName = "cond_" + cond.getColumnName();

			Element ifElement = null;
			if (!isRequired) {
				ifElement = trimElement.addElement("if");
				ifElement.addAttribute("test", condName + " != null");
			}

			StringBuilder condText = new StringBuilder();
			if (i > 0) {
				condText.append("and ");
			}
			condText.append(cond.getColumnName());
			String operator = cond.getOperator();
			if ("eq".equals(operator)) {
				condText.append(" = ");
			} else if ("ne".equals(operator)) {
				condText.append(" <> ");
			} else if ("ge".equals(operator)) {
				condText.append(" >= ");
			} else if ("gt".equals(operator)) {
				condText.append(" > ");
			} else if ("lt".equals(operator)) {
				condText.append(" < ");
			} else if ("le".equals(operator)) {
				condText.append(" <= ");
			} else if ("lkf".equals(operator)) {
				condText.append(" like '%' || ");
			} else if ("lkm".equals(operator)) {
				condText.append(" like '%' || ");
			} else if ("lkb".equals(operator)) {
				condText.append(" like ");
			} else {
				condText.append(" @@@@ ");
			}

			condText.append("#{");
			condText.append(condName);
			condText.append("}");

			if ("lkm".equals(operator)) {
				condText.append(" || '%'");
			} else if ("lkb".equals(operator)) {
				condText.append(" || '%'");
			}

			if (!isRequired) {
				ifElement.addText(condText.toString());
			} else {
				element.addText(condText.toString());
			}
		}
	}

	private String createInsertColClause(List<BindBean> bindList) {
		if (bindList == null) {
			return "";
		}

		List<String> colList = new ArrayList<String>();
		StringBuilder statment = new StringBuilder();
		for (BindBean bind : bindList){
			if (!colList.contains(bind.getColumnName())) {
				colList.add(bind.getColumnName());
			}
		}
		for (int i = 0; i < colList.size(); i++) {
			statment.append(colList.get(i));
			if (i < colList.size() - 1) {
				statment.append(",");
			}
		}
		return statment.toString();
	}

	private String createInsertValueClause(List<BindBean> bindList) {
		if (bindList == null) {
			return "";
		}

		List<String> colList = new ArrayList<String>();
		StringBuilder statment = new StringBuilder();
		for (BindBean bind : bindList){
			if (!colList.contains(bind.getColumnName())) {
				colList.add("col_" + bind.getColumnName());
			}
		}
		for (int i = 0; i < colList.size(); i++) {
			statment.append("#{");
			statment.append(colList.get(i));
			statment.append("}");
			if (i < colList.size() - 1) {
				statment.append(",");
			}
		}
		return statment.toString();
	}

	private void createUpdateColClause(Element element, List<BindBean> bindList) {
		if (bindList == null) {
			return;
		}

		String colName;
		for (int i = 0; i < bindList.size(); i++) {
			BindBean bind = bindList.get(i);

			// bind用の変数
			colName = "col_" + bind.getColumnName();

			Element ifElement = element.addElement("if");
			ifElement.addAttribute("test", colName + " != null");

			StringBuilder colText = new StringBuilder();
			if (i > 0) {
				colText.append(", ");
			}
			colText.append(bind.getColumnName());
			colText.append(" = ");
			colText.append("#{");
			colText.append(colName);
			colText.append("}");
			ifElement.addText(colText.toString());
		}
	}

	private String createDeleteWhereClause(List<ConditionBean> condList) {
		if (condList == null) {
			return "";
		}

		String condName;
		StringBuilder condText = new StringBuilder();
		for (int i = 0; i < condList.size(); i++) {
			ConditionBean cond = condList.get(i);

			// bind用の変数
			condName = "cond_" + cond.getColumnName();

			if (i > 0) {
				condText.append("and ");
			}
			condText.append(cond.getColumnName());
			String operator = cond.getOperator();
			if ("eq".equals(operator)) {
				condText.append(" = ");
			} else if ("ne".equals(operator)) {
				condText.append(" <> ");
			} else if ("gt".equals(operator)) {
				condText.append(" >= ");
			} else if ("lt".equals(operator)) {
				condText.append(" < ");
			} else if ("le".equals(operator)) {
				condText.append(" <= ");
			} else if ("lkf".equals(operator)) {
				condText.append(" like '%' || ");
			} else if ("lkm".equals(operator)) {
				condText.append(" like '%' || ");
			} else if ("lkb".equals(operator)) {
				condText.append(" like ");
			}

			condText.append("#{");
			condText.append(condName);
			condText.append("}");

			if ("lkm".equals(operator)) {
				condText.append(" || '%'");
			} else if ("lkb".equals(operator)) {
				condText.append(" || '%'");
			}
		}

		return condText.toString();
	}

	private void createSortClause(Element element, List<String> sortList) {
		if (sortList == null) {
			return;
		}

		Element ifElement = element.addElement("if");
		ifElement.addAttribute("test", "sort != null");

		StringBuilder sortText = new StringBuilder();
		for (int i = 0; i < sortList.size(); i++) {
			if (i > 0) {
				sortText.append(", ");
			}
			sortText.append(sortList.get(i));
		}
		ifElement.addText(sortText.toString());
	}

	private void outputMybatisConfig(List<String> mapperList){
		SAXReader reader = new SAXReader();
		try {
			File file = new File(AppConstants.MYBATIS_CONFIG_FILE_PATH).getAbsoluteFile();
			Document document = reader.read(file);
			Element mappersElement = (Element) document.selectSingleNode("//mappers");

			// mappers配下の要素を一旦削除する
			Iterator iterator = mappersElement.elementIterator();
			while (iterator.hasNext()) {
				Element childElement = (Element) iterator.next();
				mappersElement.remove(childElement);
			}

			mappersElement.addElement("mapper").addAttribute("resource",
					"jp/co/headwaters/webappos/dao/schema_column-mapper.xml");
			mappersElement.addElement("mapper").addAttribute("resource",
					"jp/co/headwaters/webappos/dao/system_constant-mapper.xml");
			// TODO:とりあえず
			mappersElement.addElement("mapper").addAttribute("resource",
					"jp/co/headwaters/webappos/dao/company-mapper.xml");

			for (String mapper : mapperList) {
				Element mapperElement = mappersElement.addElement("mapper");
				mapperElement.addAttribute("resource", mapper);
			}

			OutputFormat outputFormat = new OutputFormat("\t", true, "UTF-8");
			XMLWriter xw = null;
			try {
				xw = new XMLWriter(new FileWriter(file), outputFormat);
				xw.write(document);
				xw.flush();
			} catch (IOException e) {
				// TODO:WARNログを出力する
				e.printStackTrace();
			} finally {
				if (xw != null) {
					try {
						xw.close();
					} catch (IOException e) {
						// ignore
					}
				}
			}
		} catch (DocumentException e) {
			// TODO:WARNログを出力する
			e.printStackTrace();
		}
	}

	private String getOperatorString(String operator) {
		String result = "=";
		if ("eq".equals(operator)) {
			result = " == ";
		} else if ("ne".equals(operator)) {
			result = " != ";
		} else if ("gt".equals(operator)) {
			result = " ＞ ";
		} else if ("ge".equals(operator)) {
			result = " ＞= ";
		} else if ("lt".equals(operator)) {
			result = " ＜ ";
		} else if ("le".equals(operator)) {
			result = " ＜= ";
		}
		return result;
	}

	private void convertPath(Attribute attr){
		logger.debug("attr.getValue():" + attr.getValue());
		if (attr == null || attr.getValue() == null) {
			return;
		}
		String value = attr.getValue();
		if (value.indexOf(AppConstants.WEB_ROOT_DIR) < 0){
			return;
		}
		String replaceValue = _event.getServletContext().getContextPath() +
				value.substring(value.indexOf(AppConstants.WEB_ROOT_DIR) + AppConstants.WEB_ROOT_DIR.length());

		logger.debug("attr.getName():" + attr.getName());
		logger.debug("replaceValue:" + replaceValue);
		attr.getParent().addAttribute(attr.getName(), replaceValue);
	}
}
