package com.fp.hbm.helper;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;

import com.fp.persistence.commondb.exception.CommondbException;
import com.fp.persistence.commondb.helper.FormatDates;

public class PersistenceMetadata {
	private Configuration cfg;
	public PersistenceMetadata(Configuration pConf){
		this.cfg=pConf;
	}
	private PersistentClass getPresistenceClass(String pName) throws CommondbException{
		PersistentClass c=cfg.getClassMapping(pName);
		if(c==null){
			throw new CommondbException("COMMONDB-0009","EL BEAN {0} NO SE ENCUENTRA EN EL SESSIONFACTORY",pName);
		}
		return c;
	}
	 /**
   * Entrega el nombre de la propiedad del Bean que hace referencia al Campo Dado
   * @param pBean Clase de tipo Bean
   * @param pField Campo de la Tabla
   * @return Propiedad del Bean.
	 * @throws CommonException
   * @throws Exception
   */
@SuppressWarnings("rawtypes")
public String getJavaProperty(Class pBean,String pField) throws CommondbException {
    PersistentClass c=getPresistenceClass(pBean.getName());
    Iterator it=c.getKey().getColumnIterator();
    int cont = 0;
    while(it.hasNext()) {
      it.next();
      cont ++;
    }
        it=c.getKey().getColumnIterator();
    while(it.hasNext()){
      Column col=(Column)it.next();
      if(col.getName().toUpperCase().compareTo(pField.toUpperCase()) == 0){
        if (cont == 1){
      return "pk";
    }

        return "pk."+pField.toLowerCase();
      }
    }
    return pField.toLowerCase();
  }

@SuppressWarnings("rawtypes")
public String getFieldName(Class pBean,String pField) throws CommondbException {
	    PersistentClass c=getPresistenceClass(pBean.getName());
	    Iterator it=c.getPropertyIterator();
	    if(pField.toLowerCase().indexOf("pk.")>-1){
	    	pField=pField.substring(pField.toLowerCase().indexOf("pk.")+3);
	    	it=c.getKey().getColumnIterator();
	    	while (it.hasNext()) {
				Column element = (Column) it.next();
				if(element.getName().compareTo(pField)==0){
					return element.getName().toUpperCase();
				}
			}
	    	throw new CommondbException("","");
	    }
	    if(pField.compareToIgnoreCase("pk")==0){
	    	it=c.getKey().getColumnIterator();
	    	Column col = (Column)it.next();
	    	if(it.hasNext()){
	    		throw new CommondbException("","");
	    	}
      	    return col.getName().toUpperCase();
	    }
	    while(it.hasNext()){
	      Property col=(Property)it.next();
	      if(col.getName().compareToIgnoreCase(pField.toUpperCase()) == 0){
	             return pField.toUpperCase();
	      }
	    }
	    throw new CommondbException("","");
	  }
  /**
   * Verifica si un campo es un atributo del bean.
   * @param pBean   Nombre del bean que maneja la persistencia de una tabla
   * @param pCampo  Campo de la Tabla
   * @return
 * @throws CommonException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public boolean isJavaProperty(Class pBean,String pField) throws CommondbException {
    PersistentClass c=getPresistenceClass(pBean.getName());
    Iterator it=c.getTable().getColumnIterator();
    while(it.hasNext()){
      Column col=(Column)it.next();
      if(col.getName().toUpperCase().compareTo(pField.toUpperCase()) == 0){
        return true;
      }
    }
    return false;
  }
  /**
   * Entrega el nombre del campo de una tabla. Si la tabla tiene un unicampo campo que forma parte del primary key de la misma.
   * @param pBean   Nombre del bean que maneja la persistencia de una tabla.
   * @return
 * @throws CommonException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public String getFieldnameByPkSingleField(Class pBean) throws CommondbException {
    PersistentClass c=getPresistenceClass(pBean.getName());
    Iterator it=c.getKey().getColumnIterator();
    int cont = 0;
    Column col = null;
    while(it.hasNext()) {
      col = (Column)it.next();
      cont ++;
    }
    if (cont == 1){
      return col.getName().toUpperCase();
    }
    if(cont > 1){
      throw new CommondbException("COMMONDB-00010","TABLA {0} TIENE UN PRIMARY KEY COMPUESTO ",c.getTable().getName().toUpperCase());
    }
    return null;
  }

  /**
   * Entrega un lista de campos que forman el primary key de una tabla.
   * @param pBean   Nombre del bean que maneja la persistencia de una tabla.
   * @return  lFieldspk
 * @throws CommonException
   * @throws Exception
   */
 
@SuppressWarnings("rawtypes")
public List<String> getFieldsPrimaryKey(Class pBean) throws CommondbException {
    PersistentClass c=getPresistenceClass(pBean.getName());
    Iterator it=c.getKey().getColumnIterator();
    Column col = null;
    List<String> lFieldspk = new ArrayList<String>();
    while(it.hasNext()) {
      col = (Column)it.next();
      lFieldspk.add(col.getName().toUpperCase());
    }
    return lFieldspk;
  }

  /**
   * Enterga el campo que maneja el versionamiento de un bean.
   * @param pBean   Clase de tipo Bean
   * @return
 * @throws CommonException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public String getFieldVersion(Class pBean) throws CommondbException  {
    PersistentClass c=getPresistenceClass(pBean.getName());
    String version = null;
    if(c.getVersion() != null){
      version = c.getVersion().getName();
    }
    return version;
  }

  /**
   * Enterga el nombre de la tabla de un bean.
   * @param pBean   Clase de tipo Bean
   * @return
 * @throws CommonException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public String getTableName(Class pBean) throws CommondbException  {
    PersistentClass c=getPresistenceClass(pBean.getName());
    String table = c.getTable().getName().toUpperCase();
    return table;
  }
  public String getClassName(String pName) throws CommondbException{
	  return this.getPresistenceClass(pName).getClassName();
  }

  /**
   * Enterga el bean que maneja una tabla.
   * @param pTablename   Nombre de la tabla.
   * @return  Nombre de la clase que implementa el Bean
 * @throws CommonException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public String getBeanname(String pTablename) throws CommondbException  {
    Iterator itr = cfg.getClassMappings();
    String bean = null;
    while (itr.hasNext()) {
      RootClass rc = (RootClass)itr.next();
      if(rc.getTable().getName().toUpperCase().compareTo(pTablename.toUpperCase()) == 0){
        bean = rc.getClassName();
      }
    }
    if(bean == null){
      throw new CommondbException("COMMONDB-00011","BEAN NO DEFINIDO PARA LA TABLA {0}  ",pTablename);
    }
    return bean;
  }
  /**
   * Transforma el valor al tipo de dato del tabla.campo.
   * @param pBean   Nombre del bean que maneja l apersistencia de una tabla.
   * @param pCampo  Nombre de un campo que pertenece a una tabla manejada por el bean.
   * @param pValue  Valor del campo, puede estar en un tipo de dato distinto al de la tabla.
   * @return  newvalue  Valor con el tipo de dato del campo en la tabla.
 * @throws CommonException
 * @throws ParseException
 * @throws ClassNotFoundException
 * @throws NoSuchFieldException
 * @throws SecurityException
   * @throws Exception
   */

@SuppressWarnings("rawtypes")
public Object convertValueType(String pBean,String pCampo,Object pValue) throws CommondbException, ParseException, SecurityException, NoSuchFieldException, ClassNotFoundException {
    Object newvalue = null;
    String type = "";
    if(pCampo.compareTo("pk")!=0){
    PersistentClass c=getPresistenceClass(pBean);
    Iterator it=c.getTable().getColumnIterator();
    Column column = null;
    boolean find = false;
    while (it.hasNext()){
      column = (Column)it.next();
      if(column.getName().toUpperCase().compareTo(pCampo.toUpperCase()) == 0){
        find = true;
        break;
      }
    }
    if(!find){
      throw new CommondbException("COMMONDB-00012","CAMPO {0} NO DEFINIDO EN LA TABLA {1}",pCampo,c.getTable().getName());
    }
    SimpleValue simplevalue = (SimpleValue)column.getValue();
    type = simplevalue.getTypeName();
    }else{
    	type=Class.forName(pBean).getDeclaredField(pCampo).getType().getName();
    }
    if(pValue.getClass().getName().compareTo(type) == 0 ){
      newvalue = pValue;
    }else{
      if(type.compareTo("java.lang.String") == 0 ){
        newvalue = pValue;
      }
      if(type.compareTo("java.lang.Integer") == 0 ){
        newvalue = new Integer(pValue.toString());
      }
      if(type.compareTo("java.math.BigDecimal") == 0 ){
        DecimalFormatSymbols dfs = new DecimalFormatSymbols();
        dfs.setDecimalSeparator('.');
        dfs.setGroupingSeparator(',');
        DecimalFormat df = new DecimalFormat("##############.#######",dfs);
        newvalue = new BigDecimal(df.parse(pValue.toString()).doubleValue());
      }
      if(type.compareTo("java.sql.Date") == 0 ){
        SimpleDateFormat sdf = FormatDates.getInstance().getTransportDatetimeFormat();
        newvalue = new Date(sdf.parse(pValue.toString()).getTime());
      }
      if(type.compareTo("java.sql.Timestamp") == 0 ){
        SimpleDateFormat sdf = FormatDates.getInstance().getTransportDatetimeFormat();
        try{
        	String valor=pValue.toString();
        	if(valor.length()==10){
        		valor+=" 00:00:00.0";
        	}
        	newvalue = new Timestamp(sdf.parse(valor).getTime());

        }catch(Exception ex){
        	ex.printStackTrace();
        }
      }
    }
    return newvalue;
  }
}
