/*
 * 作成日: 2008/08/05
 * 著作権: Copyright (c) 2005 ZIGEN
 * ライセンス：Eclipse Public License - v 1.0
 * 原文：http://www.eclipse.org/legal/epl-v10.html
 */
package zigen.plugin.db.ext.s2jdbc.entity;

import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

import zigen.plugin.db.core.IDBConfig;
import zigen.plugin.db.core.Transaction;
import zigen.plugin.db.ext.s2jdbc.entity.rule.DefaultEntityMappingFactory;
import zigen.plugin.db.ext.s2jdbc.entity.rule.IEntityMappingFactory;
import zigen.plugin.db.ext.s2jdbc.util.CodeCreatorUtil;
import zigen.plugin.db.ext.s2jdbc.util.CommentUtil;
import zigen.plugin.db.ext.s2jdbc.util.PropertyNameUtil;
import zigen.plugin.db.ui.internal.Column;
import zigen.plugin.db.ui.internal.TreeLeaf;

public class GenerateEntityAction extends AbstractGenerateByTableAction {
	
	@Override
	protected String getTypeName() {
		return PropertyNameUtil.getEntityName(entity.getName());
	}
	
	public String getTitle() {
		return Messages.getString("GenerateEntityAction.Title"); //$NON-NLS-1$
		
	}
	
	public String getMessage() {
		return Messages.getString("PackageSelectDialog.Message"); //$NON-NLS-1$
	}
	
	protected String constructCUContent(ICompilationUnit cu, String typeContent, String lineDelimiter) throws CoreException {
		StringBuffer sb = new StringBuffer();
		sb.append("/**").append("\r\n");
		sb.append(" * ").append(entity.getLabel()).append("\r\n");
		sb.append(" *").append("\r\n");
		sb.append(" */");
		
		String typeComment = sb.toString();
		
		IPackageFragment pack = (IPackageFragment) cu.getParent();
		StringBuffer buf = new StringBuffer();
		if (!pack.isDefaultPackage())
			buf.append("package ").append(pack.getElementName()).append(';'); //$NON-NLS-1$
		buf.append(lineDelimiter).append(lineDelimiter);
		if (typeComment != null)
			buf.append(typeComment).append(lineDelimiter);
		
		// Entityアノテーションを追加
		// テーブル名は小文字にすること
		String anotation = "@Entity(name = \"" + entity.getName().toLowerCase() + "\")"; //$NON-NLS-1$ //$NON-NLS-2$
		buf.append(anotation).append(lineDelimiter);
		buf.append(typeContent);
		return buf.toString();
	}
	
	@Override
	protected void createTypeMembers(IType type, ImportsManager imports, SubProgressMonitor monitor) throws JavaModelException {
		monitor.setTaskName("Entityクラスの生成");
		imports.addImport("javax.persistence.Entity"); //$NON-NLS-1$
		// プロパティフィールドの作成
		createField(type, imports, monitor);
		// super.createTypeMembers(type, imports, monitor);
		StringBuffer buf = new StringBuffer();
		// do_toString(buf);
		// type.createMethod(buf.toString(), null, false, null);
		if (monitor != null)
			monitor.done();
	}
	
	protected String accessModifiers = "public"; // 初期値 public //$NON-NLS-1$
	
	private void createField(IType type, ImportsManager imports, IProgressMonitor monitor) throws JavaModelException {
		IEntityMappingFactory mapping = DefaultEntityMappingFactory.getFactory(entity.getDbConfig());
		StringBuffer buf = new StringBuffer();
		TreeLeaf[] leafs = entity.getChildrens();
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			
			String propertyName = PropertyNameUtil.getProperty(col, true);
			// if (!superClassFields.contains(propertyName)) {
			buf.append("\t/**").append(lineDelimiter); //$NON-NLS-1$
			buf.append("\t * " + CodeCreatorUtil.getLogicalColumnLabel(col)).append(lineDelimiter); //$NON-NLS-1$
			buf.append("\t */").append(lineDelimiter); //$NON-NLS-1$
			if ("version".equalsIgnoreCase(col.getName())) { //$NON-NLS-1$
				buf.append("\t@").append(imports.addImport("javax.persistence.Version")).append(lineDelimiter); //$NON-NLS-1$ //$NON-NLS-2$
				buf.append("\tpublic Long version = 0L;").append(lineDelimiter); //$NON-NLS-1$
			} else {
				if (col.hasPrimaryKey()) {
					buf.append("\t@").append(imports.addImport("javax.persistence.Id")).append(lineDelimiter); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				}
				buf.append("\t@").append(imports.addImport("javax.persistence.Column")).append("(name = \"" + col.getName() + "\")").append(lineDelimiter); // $NON-NlineDelimiter-1$
				// //$NON-NlineDelimiter-2$
				// //$NON-NlineDelimiter-3$
				// //$NON-NlineDelimiter-4$
				if (mapping.isLargeObject(col.getDataType())) {
					buf.append("\t@").append(imports.addImport("javax.persistence.Lob")).append(lineDelimiter); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				}
				String temporalType = mapping.getTemporalType(col.getDataType());
				if (temporalType != null) {
					imports.addImport("javax.persistence.TemporalType"); // $NON-NlineDelimiter-1$
					buf.append("\t@").append(imports.addImport("javax.persistence.Temporal")).append("(" + temporalType + ")").append(lineDelimiter);; // $NON-NlineDelimiter-1$
					// //$NON-NlineDelimiter-2$
					// //$NON-NlineDelimiter-3$
					// //$NON-NlineDelimiter-4$
				}
				
				String javaType = getJavaType(col);
				if (javaType.startsWith("java.math.") || javaType.startsWith("java.sql.")) { // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
					javaType = imports.addImport(javaType);
				}
				buf.append("\t").append(propertyString(accessModifiers, javaType, propertyName)); // $NON-NlineDelimiter-1$
				buf.append(lineDelimiter);
				
			}
			buf.append(lineDelimiter);
			
			// コメントに記載されているアノテーションから出力
			String remarks = col.getRemarks();
			if (remarks != null && !"".equals(remarks.trim())) { // $NON-NlineDelimiter-1$
				String ano = CommentUtil.getAnnotation(remarks);
				if (ano != null) {
					if ("@ManyToOne".equalsIgnoreCase(ano)) { // $NON-NlineDelimiter-1$
						String entityName = PropertyNameUtil.getEntityFromIdName(col.getName());
						
						buf.append("\t@").append(imports.addImport("javax.persistence.ManyToOne")); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
						buf.append(lineDelimiter);
						// buf.append("\t@").append(imports.addImport("javax.persistence.JoinColumn")).append("(name = \"" + PropertyNameUtil.getPropertyName(col.getName()) + "\")");
						buf.append("\t@").append(imports.addImport("javax.persistence.JoinColumn")).append("(name = \"" + col.getName() + "\")"); // $NON-NlineDelimiter-1$
						// //$NON-NlineDelimiter-2$
						// //$NON-NlineDelimiter-3$
						// //$NON-NlineDelimiter-4$
						buf.append(lineDelimiter);
						buf.append("\t").append("public ").append(entityName + " " + PropertyNameUtil.getPropertyName(entityName)).append(";"); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
						// //$NON-NlineDelimiter-3$ //$NON-NlineDelimiter-4$
						buf.append(lineDelimiter);
						
					} else if ("@OneToOne".equalsIgnoreCase(ano)) { // $NON-NlineDelimiter-1$
						String entityName = PropertyNameUtil.getEntityFromIdName(col.getName());
						
						buf.append("\t@").append(imports.addImport("javax.persistence.OneToOne")); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
						buf.append(lineDelimiter);
						// buf.append("\t@").append(imports.addImport("javax.persistence.JoinColumn")).append("(name = \"" + PropertyNameUtil.getPropertyName(col.getName()) + "\")");
						buf.append("\t@").append(imports.addImport("javax.persistence.JoinColumn")).append("(name = \"" + col.getName() + "\")"); // $NON-NlineDelimiter-1$
						// //$NON-NlineDelimiter-2$
						// //$NON-NlineDelimiter-3$
						// //$NON-NlineDelimiter-4$
						buf.append(lineDelimiter);
						buf.append("\t").append("public ").append(entityName + " " + PropertyNameUtil.getPropertyName(entityName)).append(";"); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
						// //$NON-NlineDelimiter-3$ //$NON-NlineDelimiter-4$
						buf.append(lineDelimiter);
					} else {
						boolean b = false;
						if (ano.indexOf("@OneToOne") >= 0) {
							imports.addImport("javax.persistence.OneToOne");
							b = true;
						}
						if (ano.indexOf("@OneToMany") >= 0) {
							imports.addImport("javax.persistence.OneToMany");
							b = true;
						}
						if (ano.indexOf("@ManyToOne") >= 0) {
							imports.addImport("javax.persistence.ManyToOne");
							b = true;
						}
						if (ano.indexOf("@JoinColumn") >= 0) {
							imports.addImport("javax.persistence.JoinColumn");
							b = true;
						}
						if (b) {
							buf.append("	/**").append(lineDelimiter);
							buf.append("	 * <関連アノテーション>").append(lineDelimiter);
							buf.append("	 */");
							buf.append(lineDelimiter).append(ano).append(lineDelimiter);
						}
					}
				}
				
			}
			
			buf.append(lineDelimiter);
			
			// }
		}
		
		try {
			IDBConfig config = entity.getDbConfig();
			String schema = config.getSchema();
			String columnName = entity.getName().toUpperCase() + "_ID"; // $NON-NlineDelimiter-1$
			Transaction trans = Transaction.getInstance(config);
			List<String> oneToManys = OneToManySearcher.execute(trans.getConnection(), schema, columnName);
			for (String tableName : oneToManys) {
				String myEntityName = PropertyNameUtil.getPropertyName(entity.getName()); // mKuni
				String targetEntityName = PropertyNameUtil.getEntityName(tableName); // MBu
				buf.append("\t@").append(imports.addImport("javax.persistence.OneToMany")); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append("(mappedBy = \"" + myEntityName + "\")"); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append(lineDelimiter);
				// buf.append("\t@").append(imports.addImport("javax.persistence.JoinColumn")).append("(name = \"" + col.getName() + "\")");
				// buf.append(lineDelimiter);
				buf.append("\t").append("public "); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append(imports.addImport("java.util.List")); // $NON-NlineDelimiter-1$
				buf.append("<"); // $NON-NlineDelimiter-1$
				buf.append(targetEntityName);
				buf.append("> "); // $NON-NlineDelimiter-1$
				buf.append(PropertyNameUtil.getPropertyName(tableName)).append("List;"); // $NON-NlineDelimiter-1$
				buf.append(lineDelimiter);
			}
			buf.append(lineDelimiter);
			// for OneToOne
			List<String> oneToOnes = OneToOneSearcher.execute(trans.getConnection(), schema, columnName);
			for (String tableName : oneToOnes) {
				String myEntityName = PropertyNameUtil.getPropertyName(entity.getName()); // mKuni
				String targetEntityName = PropertyNameUtil.getEntityName(tableName); // MBu
				buf.append("\t@").append(imports.addImport("javax.persistence.OneToOne")); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append("(mappedBy = \"" + myEntityName + "\")"); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append(lineDelimiter);
				buf.append("\t").append("public "); // $NON-NlineDelimiter-1$ //$NON-NlineDelimiter-2$
				buf.append(targetEntityName);
				buf.append(" "); // $NON-NlineDelimiter-1$
				buf.append(PropertyNameUtil.getPropertyName(tableName));
				buf.append(";"); // $NON-NlineDelimiter-1$
				buf.append(lineDelimiter);
			}
			buf.append(lineDelimiter);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		type.createField(buf.toString(), null, false, null);
	}
	

}
