package zigen.plugin.db.ext.jdt.vo;

import org.eclipse.jface.preference.IPreferenceStore;

import zigen.plugin.db.core.TableColumn;
import zigen.plugin.db.core.TablePKColumn;
import zigen.plugin.db.ext.jdt.Activator;
import zigen.plugin.db.ext.jdt.CodeGenerator;
import zigen.plugin.db.ext.jdt.ui.GeneratePreferencePage;
import zigen.plugin.db.ext.jdt.vo.rule.DefaultVOMappingFactory;
import zigen.plugin.db.ext.jdt.vo.rule.IVOMappingFactory;
import zigen.plugin.db.ui.internal.Column;
import zigen.plugin.db.ui.internal.ITable;
import zigen.plugin.db.ui.internal.TreeLeaf;

public class VOGenerator extends CodeGenerator {

	private String prefix = "Vo"; //$NON-NLS-1$

	private ITable table;

	private TreeLeaf[] leafs;

	boolean underLineCut = false;

	String accessModifiers = "private"; // //$NON-NLS-1$

	IVOMappingFactory mapping;

	public VOGenerator(ITable table) {
		IPreferenceStore store = Activator.getDefault().getPreferenceStore();
		underLineCut = store.getBoolean(GeneratePreferencePage.P_UNDER_LINE_CUT);
		accessModifiers = store.getString(GeneratePreferencePage.P_ACCESS_MODIFIERS);
		this.table = table;
		this.leafs = table.getChildrens();

		this.mapping = DefaultVOMappingFactory.getFactory(table.getDbConfig());
	}

	private void do_property() {
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			println("\t/**"); //$NON-NLS-1$
			println("\t * " + col.getLogicalColumnLabel()); //$NON-NLS-1$
			println("\t */"); //$NON-NLS-1$
			println("\t" + propertyString(accessModifiers, getJavaType(col), getProperty(col))); //$NON-NLS-1$
			println();
		}
	}

	private void do_method() {
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			getMethod(getJavaType(col), getProperty(col));
			setMethod(getJavaType(col), getProperty(col));
		}
	}

	private void do_import() {
		println("import java.io.Serializable;"); //$NON-NLS-1$
		// println("import java.math.BigDecimal;");
		// println("import java.util.Date;");
		println();

	}

	private void do_classBegin() {
		println("public class " + getClassName() + " implements Serializable{"); //$NON-NLS-1$ //$NON-NLS-2$
		println();
	}

	private void do_classEnd() {
		println("}"); //$NON-NLS-1$
	}

	private void do_tableDefine() {
		println("\t" + "public static final String TABLE = \"" + table.getName().toUpperCase() + "\";"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		println();
	}

	public void execute() {
		super.setGenerateInfo();
		do_import();
		super.setClassComment();
		do_classBegin();
		do_tableDefine();
		do_property();
		do_constractor();
		if (hasPrimaryKey()) {
			do_constractor2();
		}
		do_method();
		do_toString();
		do_classEnd();
	}

	private void do_constractor() {
		println("\t" + "/**"); //$NON-NLS-1$ //$NON-NLS-2$
		println("\t" + "* Constractor"); //$NON-NLS-1$ //$NON-NLS-2$
		println("\t" + "*/"); //$NON-NLS-1$ //$NON-NLS-2$
		println("\t" + "public " + getClassName() + "(){}"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		println();
	}

	private void do_constractor2() {
		println("\t" + "/**"); //$NON-NLS-1$ //$NON-NLS-2$
		println("\t" + "* Constractor"); //$NON-NLS-1$ //$NON-NLS-2$
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			if (col.getPkColumn() != null) {
				println("\t" + "* @param <code>" + getProperty(col) + "</code>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			}
		}
		println("\t" + "*/"); //$NON-NLS-1$ //$NON-NLS-2$
		print("\t" + "public " + getClassName() + "("); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		int pkCount = 0;
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			if (col.getPkColumn() != null) {
				if (pkCount == 0) {
					print(getJavaType(col) + " " + getProperty(col)); //$NON-NLS-1$
				} else {
					print(", " + getJavaType(col) + " " + getProperty(col)); //$NON-NLS-1$ //$NON-NLS-2$
				}
				pkCount++;
			}

		}
		println("){"); //$NON-NLS-1$

		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			if (col.getPkColumn() != null) {
				println("\t\t" + "this." + getProperty(col) + " = " + getProperty(col) + ";"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
			}

		}
		println("\t" + "}"); //$NON-NLS-1$ //$NON-NLS-2$

		println();
	}

	public String getClassName() {
		String str = table.getName();
		StringBuffer sb = new StringBuffer();
		sb.append(str.substring(0, 1).toUpperCase());
		sb.append(str.substring(1, str.length()).toLowerCase());
		sb.append(prefix); // prefix(VO)
		return sb.toString();
	}

	private void getMethod(String type, String property) {
		// getter メソッド
		println("\t" + "public " + type + " " + getterString(property) + "(){ return this." + property + "; }"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
		println();
	}

	private void setMethod(String type, String property) {
		// setter メソッド
		println("\t" + "public void " + setterString(property) + "(" + type + " " + property + "){ this." + property + " = " + property //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
				+ "; }"); //$NON-NLS-1$
		println();
	}

	private void do_toString() {
		String[] properties = new String[leafs.length];
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			properties[i] = getProperty(col);
		}
		println(toStringString(getClassName(), properties));
	}

	private String getJavaType(Column col) {
		TableColumn tCol = col.getColumn();
		return mapping.getJavaType(tCol);
	}

	private String getProperty(Column col) {
		TableColumn tCol = col.getColumn();
		if (!underLineCut) {
			return tCol.getColumnName().toLowerCase();
		} else {
			String str = tCol.getColumnName().toLowerCase();
			return removeUnderLine(str);
		}
	}

	protected String removeUnderLine(String strSrc) {
		int nLen = strSrc.length();
		StringBuffer sb = new StringBuffer(nLen * 2);
		for (int i = 0; i < nLen; i++) {
			char c = strSrc.charAt(i);
			switch (c) {
			case '_':
				if (i < nLen - 1) {
					char next = strSrc.charAt(++i);
					String s = new String(new char[] {
						next
					});
					sb.append(s.toUpperCase());
				}
				break;
			default:
				sb.append(c);
				break;
			}
		}
		return sb.toString();
	}

	private boolean hasPrimaryKey() {
		for (int i = 0; i < leafs.length; i++) {
			Column col = (Column) leafs[i];
			TablePKColumn pkColumn = col.getPkColumn();
			if (pkColumn != null) {
				return true;
			}
		}
		return false;
	}
}
