package com.fp.persistence.pgeneral.score;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.fp.dto.hb.HibernateBean;

/** Clase que implementa la entidad de Hibernate que hace referencia a la tabla TGENEACCOUNTSCORE */
@Entity(name = "TgeneAccountScore")
@Table(name = "TGENEACCOUNTSCORE")
public class TgeneAccountScore extends com.fp.dto.AbstractDataTransport implements Serializable, HibernateBean, Cloneable {
    /**
     * HashCode asociado con la Instancia
     */
    @Transient
    private int hashValue = 0;

    /**
     * Version de la Clase
     */
    private static final long serialVersionUID = 1L;

    /**
     * Clave primaria de la Entidad TgeneAccountScore
     */
    @EmbeddedId
    private TgeneAccountScoreKey pk;

    @Column(name = "OPERATIONSTATUS", nullable = true)
    /**
     * Codigo de estatus de la operacion con el que se realiza la calificacion, ORI (Original), REF (refinanciada), RES (restructurada)
     */
    private String operationstatus;

    @Column(name = "MODULECODE", nullable = true)
    /**
     * Codigo de modulo
     */
    private String modulecode;

    @Column(name = "PRODUCTCODE", nullable = true)
    /**
     * Codigo de producto
     */
    private String productcode;

    @Column(name = "SUBPRODUCTCODE", nullable = true)
    /**
     * Codigo de subproducto
     */
    private String subproductcode;

    @Column(name = "CURRENCYCODE", nullable = true)
    /**
     * Codigo de moneda
     */
    private String currencycode;

    @Column(name = "CREDITTYPECODE", nullable = true)
    /**
     * Codigo de tipo de credito
     */
    private String credittypecode;

    @Column(name = "STATUSCODE", nullable = true)
    /**
     * Estatus de cuenta
     */
    private String statuscode;

    @Column(name = "USERCODE", nullable = true)
    /**
     * Codigo de usuario
     */
    private String usercode;

    @Column(name = "AMOUNT", nullable = true)
    /**
     * Monto base sobre el que se realiza la provision
     */
    private BigDecimal amount;

    @Column(name = "SCORE", nullable = true)
    /**
     * Codigo de calificacion actual del prestamo. Proceso automatico.
     */
    private String score;

    @Column(name = "PROVISIONPERCENT", nullable = true)
    /**
     * Porcentaje de provision constituido.Proceso automatico.
     */
    private BigDecimal provisionpercent;

    @Column(name = "PROVISIONVALUE", nullable = true)
    /**
     * Saldo de provision de la cuentaProceso automatico.
     */
    private BigDecimal provisionvalue;

    @Column(name = "MANUALSCORE", nullable = true)
    /**
     * Codigo de calificacion actual del prestamo. Calificacion manual o por medio del archivo.
     */
    private String manualscore;

    @Column(name = "MANUALPROVISIONPERCENT", nullable = true)
    /**
     * Porcentaje de provision constituido.Calificacion manual o por medio del archivo.
     */
    private BigDecimal manualprovisionpercent;

    @Column(name = "MANUALPROVISIONVALUE", nullable = true)
    /**
     * Saldo de provision de la cuenta.Calificacion manual o por medio del archivo.
     */
    private BigDecimal manualprovisionvalue;

    @Column(name = "FINALSCORE", nullable = true)
    /**
     * Codigo de calificacion actual del prestamo.Calificacion final y homologada.
     */
    private String finalscore;

    @Column(name = "FINALPROVISIONPERCENT", nullable = true)
    /**
     * Porcentaje de provision constituido.Calificacion final y homologada.
     */
    private BigDecimal finalprovisionpercent;

    @Column(name = "FINALPROVISIONVALUE", nullable = true)
    /**
     * Saldo de provision de la cuenta.Calificacion final y homologada.
     */
    private BigDecimal finalprovisionvalue;

    @Column(name = "PREVIOUSSCORE", nullable = true)
    /**
     * Codigo de calificacion actual del prestamo.Calificacion final y homologada del periodo anterior
     */
    private String previousscore;

    @Column(name = "PREVIOUSPROVISIONPERCENT", nullable = true)
    /**
     * Porcentaje de provision constituido.Calificacion final y homologada del periodo anterior
     */
    private BigDecimal previousprovisionpercent;

    @Column(name = "PREVIOUSPROVISIONVALUE", nullable = true)
    /**
     * Saldo de provision de la cuent.Calificacion final y homologada del periodo anterior
     */
    private BigDecimal previousprovisionvalue;

    @Column(name = "EXPIRATIONDATE", nullable = true)
    /**
     * Fecha de vencimiento de la menor cuota no pagada
     */
    private Date expirationdate;

    @Column(name = "ISCOMPUTEDSCORE", nullable = true)
    /**
     * N Indica que la calificacion se creo al crear la cuenta, Y Indica que es una calificacion a reportar a un organismo de control
     */
    private String iscomputedscore;

    @Column(name = "JOURNALID", nullable = false)
    /**
     * Numero de movimiento 
     */
    private String journalid;

    /** Contructor por defecto */
    public TgeneAccountScore() {
    }

    /**
     * Contructor de TgeneAccountScore
     * 
     * @param pPk Clave Primaria del entity
     * @param pJournalid Numero de movimiento
     */
    public TgeneAccountScore(TgeneAccountScoreKey pPk, String pJournalid) {
        this();
        this.pk = pPk;
        this.journalid = pJournalid;
    }

    /**
     * Metodo que entrega datos de la tabla dada la clave primaria.
     * 
     * @param pEntityManager referencia de la session a obtener datos del bean.
     * @param pKey Caleve primaria del bean.
     * @return TgeneAccountScore
     */
    public static TgeneAccountScore find(EntityManager pEntityManager, TgeneAccountScoreKey pKey) throws Exception {
        TgeneAccountScore obj = pEntityManager.find(TgeneAccountScore.class, pKey);
        return obj;
    }

    /**
     * Entrega la Clave primaria de TgeneAccountScore
     * 
     * @return El objeto que referencia a la Clave primaria de TgeneAccountScore
     */
    public TgeneAccountScoreKey getPk() {
        return this.pk;
    }

    /**
     * Fija un nuevo valor a la Clave primaria de TgeneAccountScore
     * 
     * @param pPk El objeto que referencia a la nueva Clave primaria de TgeneAccountScore
     */
    public void setPk(TgeneAccountScoreKey pPk) {
        this.pk = pPk;
    }

    /**
     * Obtiene el valor de operationstatus
     * 
     * @return valor de operationstatus
     */
    public String getOperationstatus() {
        return this.operationstatus;
    }

    /**
     * Fija el valor de operationstatus
     * 
     * @param pOperationstatus nuevo Valor de operationstatus
     */
    public void setOperationstatus(String pOperationstatus) {
        this.operationstatus = pOperationstatus;
    }

    /**
     * Obtiene el valor de modulecode
     * 
     * @return valor de modulecode
     */
    public String getModulecode() {
        return this.modulecode;
    }

    /**
     * Fija el valor de modulecode
     * 
     * @param pModulecode nuevo Valor de modulecode
     */
    public void setModulecode(String pModulecode) {
        this.modulecode = pModulecode;
    }

    /**
     * Obtiene el valor de productcode
     * 
     * @return valor de productcode
     */
    public String getProductcode() {
        return this.productcode;
    }

    /**
     * Fija el valor de productcode
     * 
     * @param pProductcode nuevo Valor de productcode
     */
    public void setProductcode(String pProductcode) {
        this.productcode = pProductcode;
    }

    /**
     * Obtiene el valor de subproductcode
     * 
     * @return valor de subproductcode
     */
    public String getSubproductcode() {
        return this.subproductcode;
    }

    /**
     * Fija el valor de subproductcode
     * 
     * @param pSubproductcode nuevo Valor de subproductcode
     */
    public void setSubproductcode(String pSubproductcode) {
        this.subproductcode = pSubproductcode;
    }

    /**
     * Obtiene el valor de currencycode
     * 
     * @return valor de currencycode
     */
    public String getCurrencycode() {
        return this.currencycode;
    }

    /**
     * Fija el valor de currencycode
     * 
     * @param pCurrencycode nuevo Valor de currencycode
     */
    public void setCurrencycode(String pCurrencycode) {
        this.currencycode = pCurrencycode;
    }

    /**
     * Obtiene el valor de credittypecode
     * 
     * @return valor de credittypecode
     */
    public String getCredittypecode() {
        return this.credittypecode;
    }

    /**
     * Fija el valor de credittypecode
     * 
     * @param pCredittypecode nuevo Valor de credittypecode
     */
    public void setCredittypecode(String pCredittypecode) {
        this.credittypecode = pCredittypecode;
    }

    /**
     * Obtiene el valor de statuscode
     * 
     * @return valor de statuscode
     */
    public String getStatuscode() {
        return this.statuscode;
    }

    /**
     * Fija el valor de statuscode
     * 
     * @param pStatuscode nuevo Valor de statuscode
     */
    public void setStatuscode(String pStatuscode) {
        this.statuscode = pStatuscode;
    }

    /**
     * Obtiene el valor de usercode
     * 
     * @return valor de usercode
     */
    public String getUsercode() {
        return this.usercode;
    }

    /**
     * Fija el valor de usercode
     * 
     * @param pUsercode nuevo Valor de usercode
     */
    public void setUsercode(String pUsercode) {
        this.usercode = pUsercode;
    }

    /**
     * Obtiene el valor de amount
     * 
     * @return valor de amount
     */
    public BigDecimal getAmount() {
        return this.amount;
    }

    /**
     * Fija el valor de amount
     * 
     * @param pAmount nuevo Valor de amount
     */
    public void setAmount(BigDecimal pAmount) {
        this.amount = pAmount;
    }

    /**
     * Obtiene el valor de score
     * 
     * @return valor de score
     */
    public String getScore() {
        return this.score;
    }

    /**
     * Fija el valor de score
     * 
     * @param pScore nuevo Valor de score
     */
    public void setScore(String pScore) {
        this.score = pScore;
    }

    /**
     * Obtiene el valor de provisionpercent
     * 
     * @return valor de provisionpercent
     */
    public BigDecimal getProvisionpercent() {
        return this.provisionpercent;
    }

    /**
     * Fija el valor de provisionpercent
     * 
     * @param pProvisionpercent nuevo Valor de provisionpercent
     */
    public void setProvisionpercent(BigDecimal pProvisionpercent) {
        this.provisionpercent = pProvisionpercent;
    }

    /**
     * Obtiene el valor de provisionvalue
     * 
     * @return valor de provisionvalue
     */
    public BigDecimal getProvisionvalue() {
        return this.provisionvalue;
    }

    /**
     * Fija el valor de provisionvalue
     * 
     * @param pProvisionvalue nuevo Valor de provisionvalue
     */
    public void setProvisionvalue(BigDecimal pProvisionvalue) {
        this.provisionvalue = pProvisionvalue;
    }

    /**
     * Obtiene el valor de manualscore
     * 
     * @return valor de manualscore
     */
    public String getManualscore() {
        return this.manualscore;
    }

    /**
     * Fija el valor de manualscore
     * 
     * @param pManualscore nuevo Valor de manualscore
     */
    public void setManualscore(String pManualscore) {
        this.manualscore = pManualscore;
    }

    /**
     * Obtiene el valor de manualprovisionpercent
     * 
     * @return valor de manualprovisionpercent
     */
    public BigDecimal getManualprovisionpercent() {
        return this.manualprovisionpercent;
    }

    /**
     * Fija el valor de manualprovisionpercent
     * 
     * @param pManualprovisionpercent nuevo Valor de manualprovisionpercent
     */
    public void setManualprovisionpercent(BigDecimal pManualprovisionpercent) {
        this.manualprovisionpercent = pManualprovisionpercent;
    }

    /**
     * Obtiene el valor de manualprovisionvalue
     * 
     * @return valor de manualprovisionvalue
     */
    public BigDecimal getManualprovisionvalue() {
        return this.manualprovisionvalue;
    }

    /**
     * Fija el valor de manualprovisionvalue
     * 
     * @param pManualprovisionvalue nuevo Valor de manualprovisionvalue
     */
    public void setManualprovisionvalue(BigDecimal pManualprovisionvalue) {
        this.manualprovisionvalue = pManualprovisionvalue;
    }

    /**
     * Obtiene el valor de finalscore
     * 
     * @return valor de finalscore
     */
    public String getFinalscore() {
        return this.finalscore;
    }

    /**
     * Fija el valor de finalscore
     * 
     * @param pFinalscore nuevo Valor de finalscore
     */
    public void setFinalscore(String pFinalscore) {
        this.finalscore = pFinalscore;
    }

    /**
     * Obtiene el valor de finalprovisionpercent
     * 
     * @return valor de finalprovisionpercent
     */
    public BigDecimal getFinalprovisionpercent() {
        return this.finalprovisionpercent;
    }

    /**
     * Fija el valor de finalprovisionpercent
     * 
     * @param pFinalprovisionpercent nuevo Valor de finalprovisionpercent
     */
    public void setFinalprovisionpercent(BigDecimal pFinalprovisionpercent) {
        this.finalprovisionpercent = pFinalprovisionpercent;
    }

    /**
     * Obtiene el valor de finalprovisionvalue
     * 
     * @return valor de finalprovisionvalue
     */
    public BigDecimal getFinalprovisionvalue() {
        return this.finalprovisionvalue;
    }

    /**
     * Fija el valor de finalprovisionvalue
     * 
     * @param pFinalprovisionvalue nuevo Valor de finalprovisionvalue
     */
    public void setFinalprovisionvalue(BigDecimal pFinalprovisionvalue) {
        this.finalprovisionvalue = pFinalprovisionvalue;
    }

    /**
     * Obtiene el valor de previousscore
     * 
     * @return valor de previousscore
     */
    public String getPreviousscore() {
        return this.previousscore;
    }

    /**
     * Fija el valor de previousscore
     * 
     * @param pPreviousscore nuevo Valor de previousscore
     */
    public void setPreviousscore(String pPreviousscore) {
        this.previousscore = pPreviousscore;
    }

    /**
     * Obtiene el valor de previousprovisionpercent
     * 
     * @return valor de previousprovisionpercent
     */
    public BigDecimal getPreviousprovisionpercent() {
        return this.previousprovisionpercent;
    }

    /**
     * Fija el valor de previousprovisionpercent
     * 
     * @param pPreviousprovisionpercent nuevo Valor de previousprovisionpercent
     */
    public void setPreviousprovisionpercent(BigDecimal pPreviousprovisionpercent) {
        this.previousprovisionpercent = pPreviousprovisionpercent;
    }

    /**
     * Obtiene el valor de previousprovisionvalue
     * 
     * @return valor de previousprovisionvalue
     */
    public BigDecimal getPreviousprovisionvalue() {
        return this.previousprovisionvalue;
    }

    /**
     * Fija el valor de previousprovisionvalue
     * 
     * @param pPreviousprovisionvalue nuevo Valor de previousprovisionvalue
     */
    public void setPreviousprovisionvalue(BigDecimal pPreviousprovisionvalue) {
        this.previousprovisionvalue = pPreviousprovisionvalue;
    }

    /**
     * Obtiene el valor de expirationdate
     * 
     * @return valor de expirationdate
     */
    public Date getExpirationdate() {
        return this.expirationdate;
    }

    /**
     * Fija el valor de expirationdate
     * 
     * @param pExpirationdate nuevo Valor de expirationdate
     */
    public void setExpirationdate(Date pExpirationdate) {
        this.expirationdate = pExpirationdate;
    }

    /**
     * Obtiene el valor de iscomputedscore
     * 
     * @return valor de iscomputedscore
     */
    public String getIscomputedscore() {
        return this.iscomputedscore;
    }

    /**
     * Fija el valor de iscomputedscore
     * 
     * @param pIscomputedscore nuevo Valor de iscomputedscore
     */
    public void setIscomputedscore(String pIscomputedscore) {
        this.iscomputedscore = pIscomputedscore;
    }

    /**
     * Obtiene el valor de journalid
     * 
     * @return valor de journalid
     */
    public String getJournalid() {
        return this.journalid;
    }

    /**
     * Fija el valor de journalid
     * 
     * @param pJournalid nuevo Valor de journalid
     */
    public void setJournalid(String pJournalid) {
        this.journalid = pJournalid;
    }

    @Override
    public boolean equals(Object rhs) {
        if (rhs == null) {
            return false;
        }
        if (!(rhs instanceof TgeneAccountScore)) {
            return false;
        }
        TgeneAccountScore that = (TgeneAccountScore) rhs;
        if ((this.getPk() == null) || (that.getPk() == null)) {
            return false;
        }
        return this.getPk().equals(that.getPk());
    }

    /**
     * Implementacion del metodo hashCode de la la entidad TgeneAccountScore
     * 
     * @return el hashCode la instancia
     */
    @Override
    public int hashCode() {
        if (this.hashValue == 0) {
            int result = 17;
            if (this.getPk() == null) {
                result = super.hashCode();
            } else {
                result = this.getPk().hashCode();
            }
            this.hashValue = result;
        }
        return this.hashValue;
    }

    /** Implementacion toString */
    @Override
    public String toString() {
        Field[] fs = this.getClass().getDeclaredFields();
        String data = "";
        for (Field f : fs) {
            try {
                String name = f.getName();
                if (f.getType().getName().compareTo("java.util.Set") == 0) {
                    continue;
                }
                if ((name.compareTo("hashValue") == 0) || (name.compareTo("serialVersionUID") == 0)) {
                    continue;
                }
                data += name + "=" + f.get(this) + ";";
            } catch (Exception e) {
                continue;
            }
        }
        if (data.compareTo("") == 0) {
            data = super.toString();
        }
        return data;
    }

    /** Implementacion de la creacion de un bean en blanco TgeneAccountScore */
    @Override
    public Object createInstance() {
        TgeneAccountScore instance = new TgeneAccountScore();
        instance.setPk(new TgeneAccountScoreKey());
        return instance;
    }

    /**
     * Clona la entidad TgeneAccountScore
     * 
     * @see com.fp.dto.hb.HibernateBean#cloneMe()
     */
    @Override
    public Object cloneMe() throws CloneNotSupportedException {
        TgeneAccountScore p = (TgeneAccountScore) this.clone();
        p.setPk((TgeneAccountScoreKey) this.pk.cloneMe());
        return p;
    }

    /* Métodos manuales */

    /** Sentencia para seleccionar la ultima calificación de una cuenta */
    private static final String JPQL_LAST_SCORE = " select t from TgeneAccountScore t " + " where t.pk.account = :account "
            + " and t.pk.company = :company " + " and t.modulecode = :modulecode " + " and t.pk.scoredate = ( "
            + " select max(t.pk.scoredate) from TgeneAccountScore t " + " where t.pk.account = :account " + " and t.pk.company = :company "
            + " and t.modulecode = :modulecode " + " and t.iscomputedscore = 'Y' " + " group by t.pk.account )";

    /**
     * Método que selecciona la ultima calificación de una cuenta
     * 
     * @param entityManager
     * @param pAccount
     * @param pCompany
     * @param pModulecode
     * @return
     * @throws Exception
     */
    public static TgeneAccountScore getLastScore(EntityManager entityManager, String pAccount, Integer pCompany, String pModulecode) throws Exception {
        Query qry = entityManager.createQuery(TgeneAccountScore.JPQL_LAST_SCORE);
        qry.setParameter("account", pAccount);
        qry.setParameter("company", pCompany);
        qry.setParameter("modulecode", pModulecode);

        try {
            return (TgeneAccountScore) qry.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    // Metodos personalizados

    // select * from tgeneaccountscore where account = 1 and companycode =1;

    private static final String JPQL_FIND_BY_ACCOUNT = "" + " from TgeneAccountScore tga " + "where tga.pk.account = :account "
            + "  and tga.pk.company = :company";

    /**
     * Permite consultar el registro asociado a la cuenta
     * 
     * @param entityManager Administrador de entidades y persistencia
     * @param account String con la cuenta a consultar
     * @param company int con la empresa asociada a la cuenta
     * @return Registro TgeneAccountScore
     * @throws Exception
     */
    public static TgeneAccountScore findByAccount(EntityManager entityManager, String account, int company) {
        Query qry = entityManager.createQuery(TgeneAccountScore.JPQL_FIND_BY_ACCOUNT);
        qry.setParameter("account", account);
        qry.setParameter("company", company);
        return (TgeneAccountScore) qry.getSingleResult();
    }

    private static final String JPQL_FIND_WORST_SCORE_CONSTRUCTOR = ""
            + "  from TGENEACCOUNTSCORE "
            + "  where account in (select LOANACCOUNT "
            + "                     from TCREDITFACILITYDETAILLOAN cf "
            + "                    where ACCOUNT in (select ACCOUNT from TCREDITFACILITYDETAILLOAN  where LOANACCOUNT = :account and COMPANY = :company)) "
            + "  and score in (select max(SCORE) "
            + "  from TGENEACCOUNTSCORE "
            + "  where account in (select LOANACCOUNT "
            + "                     from TCREDITFACILITYDETAILLOAN cf "
            + "                    where ACCOUNT in (select ACCOUNT from TCREDITFACILITYDETAILLOAN  where LOANACCOUNT = :account and COMPANY = :company))) ";

    @SuppressWarnings("unchecked")
    public static List<TgeneAccountScore> findByWorstScore(EntityManager entityManager, String account, int company, boolean isConstructor) {
        Query qry = entityManager.createQuery(TgeneAccountScore.JPQL_FIND_WORST_SCORE_CONSTRUCTOR);
        qry.setParameter("account", account);
        qry.setParameter("company", company);
        qry.setMaxResults(1);
        return qry.getResultList();
    }

    private static final String JPQL_FIND_WORST_SCORE = "" + "select score.* " + "  from tgeneaccountscore score inner join TGENEACCOUNT aco1  "
            + "    on score.account = aco1.account " + "   and score.company = aco1.company " + "   and score.modulecode = aco1.modulecode "
            + " inner join TGENEACCOUNT aco2 " + "    on aco1.PERSONCODE = aco2.personcode " + "   and aco1.COMPANY = aco2.COMPANY "
            + "   and aco1.DATETO = aco2.DATETO " + "   and aco2.account = :account " + "   and aco1.MODULECODE = aco2.MODULECODE "
            + "   and aco1.PRODUCTCODE = aco2.PRODUCTCODE " + "   and aco2.DATETO = aco1.DATETO " + "   and aco2.DATETO = TO_DATE('31/12/2999') "
            + "   and aco2.company = :company " + " order by score.finalscore desc";

    @SuppressWarnings("unchecked")
    public static TgeneAccountScore findByWorstScore(EntityManager entityManager, String account, int company) {
        Query qry = entityManager.createQuery(TgeneAccountScore.JPQL_FIND_WORST_SCORE);
        qry.setParameter("account", account);
        qry.setParameter("company", company);
        qry.setMaxResults(1);
        List<TgeneAccountScore> objresultado = qry.getResultList();
        if (objresultado.size() == 1) {
            return objresultado.get(0);
        } else {
            return new TgeneAccountScore();
        }
    }

    private final static String JPQL_ACCOUNT_SCORE = " from TgeneAccountScore tls where "
            + "tls.pk.account IN (:accountList) and tls.score IN (:scoreList)";

    /**
     * Permite obtener la cuentas de prestamo que esten en estado vigente y que ademas tengan el score necesario para
     * reestructuracion
     * 
     * @param entityManager Administrador de persistencia y entidades
     * @param accountList Lista de {@link String} con las cuentas a validar
     * @param scoreList Lista de {@link String} con los puntajes a validar
     * @return lista de datos {@link TloanAccountScore } con los valores de la operacion
     */
    @SuppressWarnings("unchecked")
    public static List<TgeneAccountScore> findAccountsByScore(EntityManager entityManager, List<String> accountList, List<String> scoreList) {
        Query qry = entityManager.createQuery(TgeneAccountScore.JPQL_ACCOUNT_SCORE);
        qry.setParameter("accountList", accountList);
        qry.setParameter("scoreList", scoreList);
        return qry.getResultList();
    }

}
