/**
 *
 */
package com.fp.hbm.bgenerator.ann;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import com.fp.common.exception.APPException;
import com.fp.hbm.bgenerator.AbstractColumn;
import com.fp.hbm.bgenerator.AbstractMapper;


/**
 * @author Jorge Vaca
 *
 */
public class Mapper extends AbstractMapper {

	
	
	public Mapper() {
		this.packageName = packageBase + ".";
	}

	public String getKeyClassData() throws APPException {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		pw.println("package " + this.packageName + ";");
		this.formatKeyImports(pw);
		pw.println("/**Clase que hace referencia a la Clave Primaria de " + this.table + "*/");
		pw.println("@Embeddable");
		pw.println("public class " + this.entity + "Key " + " extends com.fp.dto.AbstractDataTransport"
				+ "  implements Serializable,Cloneable,HibernateId" + ((this.history) ? ",History" : "") + "{");
		this.formatBasicsJava(pw);
		this.formatKeyJava(pw);
		this.createKeyConstructor(pw);
		this.formatKeyJavaGS(pw);
		this.formatKeyEquals(pw);
		this.formatKeyHash(pw);
		formatKeyClone(pw);
		this.formatToString(pw, "pk");
		if (this.history) {
			this.formatKeyHistoryNeededMethods(pw);
		}
		pw.println("}");
		String data = sw.toString();
		pw.close();
		return data;
	}

	private void formatClassPKData(PrintWriter pw) throws APPException {
		pw.println("/**");
		pw.println("* Clave primaria de la Entidad " + this.entity);
		pw.println("*/");
		
		if (this.isKeyClassNeeded()) {
			pw.println("@EmbeddedId");
			pw.println("private " + this.getKeyClasss() + " pk;");
		} else {
			pw.println("@Id");
			pw.println("@Column(name=\"" + this.primary.get(0).getName()+"\" ,nullable=false, updatable=false)");
			pw.println("private " + this.primary.get(0).getJavaSimple() + " pk;");
		}
	}

	private void formatClassPKDataGS(PrintWriter pw) throws APPException {
		String className = "";
		if (this.isKeyClassNeeded()) {
			className = this.getKeyClasss();
		} else {
			className = this.primary.get(0).getJavaSimple();
		}
		pw.println("/**Entrega la Clave primaria de " + this.entity);
		pw.println("@return El objeto que referencia a la Clave primaria de " + this.entity);
		pw.println("*/");
		pw.println("public " + className + " getPk(){");
		pw.println("  return pk;");
		pw.println("}");
		pw.println("/**Fija un nuevo valor a la Clave primaria de " + this.entity);
		pw.println("@param pPk El objeto que referencia a la nueva Clave primaria de " + this.entity);
		pw.println("*/");
		pw.println("public void setPk(" + className + " pPk){");
		pw.println("  pk=pPk;");
		pw.println("}");
	}

	public String getClassData() throws APPException {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		pw.println("package " + this.packageName + ";");
		this.formatClassImports(pw);
		String ext = "";
		if (this.history) {
			ext = " extends AbstractExpire ";
		}
		pw.println("/**Clase que implementa la entidad de Hibernate que hace referencia a la tabla " + this.table + "*/");
		pw.println("@Entity(name=\"" + this.entity + "\")");
		pw.println("@Table(name=\"" + this.table + "\")");
		if (this.optimistic) {
			//no se utiliza el de JPA
			//pw.println("@org.hibernate.annotations.Entity(optimisticLock=org.hibernate.annotations.OptimisticLockType.VERSION)");
		}
		if (this.isKeyClassNeeded()) {
			//Va con embeded
			//pw.println("@IdClass(value=" + this.entity + "Key.class)");
		}
		class_name = this.entity ;
		pw.println("public class " + class_name + ((this.sExtends == null) ? ext : " extends " + this.sExtends)
				+ " implements Serializable,HibernateBean,Cloneable" +(!this.cache ? "" : "," + "Cache")
				+(!this.log ? "" : "," + "Log")+
				((this.sImplements == null) ? "" : "," + this.sImplements) + "{");
		this.formatBasicsJava(pw);
		this.formatClassPKData(pw);
		this.formatColumnsJava(pw);
		this.createClassConstructor(pw);
		super.addFindMethod(pw);
		this.formatClassPKDataGS(pw);
		this.formatColumnsJavaGS(pw);
		this.formatClassCompare(pw);
		this.formatClassHash(pw);
		this.formatToString(pw, "");
		this.formatCreateInstance(pw);
		formatClassCloneable(pw);
		if (this.history) {
			this.formatHistoryNeededMethods(pw);
		}
		pw.println("}");
		String data = sw.toString();
		pw.close();
		return data;
	}

	private void formatColumnsJava(PrintWriter pw) throws APPException {
		for (AbstractColumn col : this.columns) {
			if (this.optimistic && col.getName().toUpperCase().compareTo("RECORDVERSION") == 0) {
				pw.println("@Version");
			}
			pw.println(col.formatProperty());
			pw.println(col.formatJava());
		}

	}

	private void formatClassImports(PrintWriter pw) throws APPException {
		
		
		Map<String, String> m = new HashMap<String, String>();
		m.put("import java.io.Serializable;", "");
		m.put("import java.lang.reflect.Field;", "");
		m.put("import javax.persistence.Entity;", "");
		m.put("import javax.persistence.EntityManager;", "");	
		m.put("import javax.persistence.Column;", "");
		m.put("import javax.persistence.Table;", "");
		m.put("import javax.persistence.Transient;", "");
		if (isKeyClassNeeded()) {
			m.put("import javax.persistence.EmbeddedId;", "");	
		}else{
			m.put("import javax.persistence.Id;", "");
		}
		if (this.optimistic) {
			m.put("import javax.persistence.Version;", "");	
		}				
		//m.put("import com.fitbank.common.TransportBean;", "");
		m.put("import com.fp.dto.hb.HibernateBean;", "");
		if(this.cache){
			m.put("import com.fp.dto.hb.Cache;", "");	
		}
		if(this.log){
			m.put("import com.fp.dto.hb.Log;", "");	
		}		
		if (this.history) {
			//m.put("import com.fitbank.common.hb.AbstractExpire;", "");
		}
		for (AbstractColumn col : this.columns) {
			List<String> im = col.getImportData();
			for (String dt : im) {
				m.put("import " + dt + ";", "");
			}
		}

		for (AbstractColumn col : this.primary) {
			List<String> im = col.getImportData();
			for (String dt : im) {
				m.put("import " + dt + ";", "");
			}
		}
		pw.println();
		for (String imp : m.keySet()) {
			pw.println(imp);
		}
		pw.println();
	}

	private void formatKeyImports(PrintWriter pw) throws APPException {
		Map<String, String> m = new HashMap<String, String>();
		m.put("import javax.persistence.Column;", "");
		m.put("import javax.persistence.Embeddable;", "");
		m.put("import javax.persistence.Transient;", "");
		m.put("import java.io.Serializable;", "");
		m.put("import java.lang.reflect.Field;", "");
		m.put("import com.fp.dto.hb.HibernateId;", "");		
		if (this.history) {
			m.put("import com.fp.dto.hb.History;", "");
		}
		for (AbstractColumn col : this.primary) {
			List<String> im = col.getImportData();
			for (String dt : im) {
				m.put("import " + dt + ";", "");
			}
		}
		pw.println();
		for (String imp : m.keySet()) {
			pw.println(imp);
		}
		pw.println();
	}

	private void formatColumnsJavaGS(PrintWriter pw) throws APPException {
		for (AbstractColumn col : this.columns) {
			pw.println(col.formatJavaGetSet(false));
		}

	}

	private void formatKeyJava(PrintWriter pw) throws APPException {
		for (AbstractColumn col : this.primary) {
			pw.println(col.formatProperty());
			pw.println(col.formatJava());
		}

	}

	private void formatKeyJavaGS(PrintWriter pw) throws APPException {
		for (AbstractColumn col : this.primary) {
			pw.println(col.formatJavaGetSet(true));
		}

	}

	@Override
	public void safeEntity() throws IOException, APPException {
		
		String sPath = this.parent.getPath() + "/" + this.ent.getProject() + "/src/main" + this.parent.getSoucePath()
				+ getPackageName().replaceAll("\\.", "/");
		if (isKeyClassNeeded()) {
			this.safe(getKeyClassData(), sPath, getEntity() + "Key.java");
		}
		String filename = getEntity(); 
		this.safe(getClassData(), sPath, filename + ".java");

	}

}
