package com.fp.general.db;

import java.sql.Date;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

import com.fp.common.helper.CalculationBase;
import com.fp.common.helper.Constant;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.cache.CacheManager;
import com.fp.persistence.commondb.helper.APPDates;
import com.fp.persistence.commondb.helper.FormatDates;
import com.fp.persistence.pgeneral.acco.TgeneAccount;
import com.fp.persistence.pgeneral.acco.TgeneAccountStatus;
import com.fp.persistence.pgeneral.acco.TgeneAccountStatusKey;
import com.fp.persistence.pgeneral.auth.TgeneSolicitudeClientdata;
import com.fp.persistence.pgeneral.auth.TgeneSolicitudeExceptions;
import com.fp.persistence.pgeneral.charge.TgeneCharges;
import com.fp.persistence.pgeneral.charge.TgeneSubProductCharges;
import com.fp.persistence.pgeneral.gene.TgeneBranch;
import com.fp.persistence.pgeneral.gene.TgeneSolicitude;
import com.fp.persistence.pgeneral.gene.TgeneSolicitudeRelationship;
import com.fp.persistence.pgeneral.menu.TgeneMenuLevel;
import com.fp.persistence.pgeneral.menu.TgeneMenuLevelDesc;
import com.fp.persistence.pgeneral.menu.TgeneMenuLevelTran;
import com.fp.persistence.pgeneral.menu.TgeneMenuProfile;
import com.fp.persistence.pgeneral.menu.TgeneMenuSubLevel;
import com.fp.persistence.pgeneral.menu.TgeneMenuSubLevelDesc;
import com.fp.persistence.pgeneral.product.TgeneModule;
import com.fp.persistence.pgeneral.product.TgeneProduct;
import com.fp.persistence.pgeneral.product.TgeneSubProduct;
import com.fp.persistence.pgeneral.product.TgeneSubprodClientData;
import com.fp.persistence.pgeneral.safe.TsafeUserDetail;
import com.fp.persistence.pgeneral.safe.TsafeUserProfile;
import com.fp.persistence.pgeneral.score.TgenePercentScore;
import com.fp.persistence.pgeneral.score.TgenePercentScoreKey;
import com.fp.persistence.pgeneral.score.TgeneScoreRank;

/**
 * Clase utilitaria que maneje sql y hql utiliada en el proyecto general.
 * 
 * @author Jorge Vaca
 * @version 2.1
 */
public final class DataHelper {

    /** Almacena una instancia de DataHelper. */
    private static DataHelper cache;

    /**
     * Entrega una instancia de DataHelper.
     * 
     * @return DataHelper
     */
    public static DataHelper getInstance() {
        if (DataHelper.cache != null) {
            return DataHelper.cache;
        }
        synchronized (DataHelper.class) {
            if (DataHelper.cache == null) {
                DataHelper.cache = new DataHelper();
            }
        }
        return DataHelper.cache;
    }

    /**
     * Metodo que entrega datos de una sucursal definidos en TgeneBranch.
     * 
     * @param pBranch Codigo de sucursal.
     * @param pCompany Compania a la que pertenece la cuenta.
     * @return TgeneBranch
     * @throws Exception
     */
    public TgeneBranch getTgeneBranch(Integer pBranch, Integer pCompany) throws Exception {
        return TgeneBranch.find(PersistenceHelper.getEntityManager(), pBranch, pCompany);
    }

    /**
     * Metodo que entrega datos de TgeneMenuProfile.
     * 
     * @param pProfile Codigo de perfil del usuario.
     * @return TgeneMenuProfile
     * @throws Exception
     */
    public TgeneMenuProfile getTgeneMenuProfile(String pProfile) throws Exception {
        return TgeneMenuProfile.findByCodePerfilUsuario(PersistenceHelper.getEntityManager(), pProfile);
    }

    /**
     * Metodo que entrega descripcion del primer nivel del menu.
     * 
     * @param pmenucode Codigo de menu.
     * @param pLevel Codigo de nivel.
     * @param planguagecode Codigo de lenguaje del usuario.
     * @return TgeneMenuLevelDesc
     * @throws Exception
     */
    public TgeneMenuLevelDesc getTgeneMenuLevelDesc(Integer pmenucode, Integer pLevel, String planguagecode) throws Exception {
        return TgeneMenuLevelDesc.find(PersistenceHelper.getEntityManager(), pmenucode, pLevel, planguagecode);
    }

    /**
     * Metodo que entrega la definicion del primer nivel del menu.
     * 
     * @param pMenucode Codigo de menu.
     * @return List<TgeneMenuLevel>
     * @throws Exception
     */
    public List<TgeneMenuLevel> getTgeneMenuLevel(Integer pMenucode) throws Exception {
        return TgeneMenuLevel.findByMenuCode(PersistenceHelper.getEntityManager(), pMenucode);
    }

    /**
     * Metodo que entrega uns lista de definicion del menu de segundo nivel.
     * 
     * @param pMenucode Codigo de menu.
     * @param pLevel Codigo del primer nivel.
     * @return List<TgeneMenuSubLevel>
     * @throws Exception
     */
    public List<TgeneMenuSubLevel> getTgeneMenuSuLevels(Integer pMenucode, Integer pLevel) throws Exception {
        return TgeneMenuSubLevel.find(PersistenceHelper.getEntityManager(), pMenucode, pLevel);
    }

    /**
     * Metodo que emtrega la descripcion de un subnivel del menu.
     * 
     * @param pmenucode Codigo de menu.
     * @param pLevel Codigo de nivel de menu.
     * @param pSublevel Codigo de subnivel de menu.
     * @param planguagecode Codigo de lenguaje.
     * @return TgeneMenuSubLevelDesc
     * @throws Exception
     */
    public TgeneMenuSubLevelDesc getTgeneMenuSubLevelDesc(Integer pmenucode, Integer pLevel, Integer pSublevel, String planguagecode)
            throws Exception {
        return TgeneMenuSubLevelDesc.find(PersistenceHelper.getEntityManager(), pmenucode, pLevel, pSublevel, planguagecode);
    }

    /**
     * Metodo que entrega transacciones asociadas al codigo de menu y codigo de nivel.
     * 
     * @param pMenucode Codigo de menu.
     * @param pLevel Codigo de Nivel.
     * @return List<TgeneMenuLevelTran>
     * @throws Exception
     */
    public List<TgeneMenuLevelTran> getTgeneMenuLevelTran(Integer pMenucode, Integer pLevel) throws Exception {
        return TgeneMenuLevelTran.findByCodeMenuNivel(PersistenceHelper.getEntityManager(), pMenucode, pLevel);
    }

    /**
     * Metodo que obtiene datos del perfil del usuario.
     * 
     * @param pusercode Codigo de usuario.
     * @return TsafeUserProfile
     * @throws Exception
     */
    public List<TsafeUserProfile> getTsafeUserProfile(String pusercode) throws Exception {
        return TsafeUserProfile.find(PersistenceHelper.getEntityManager(), pusercode);
    }

    /**
     * Metodo que obtiene datos de un registro del modulo.
     * 
     * @param pModulecode Codigo de modulo a obtener datos de la base.
     * @return TgeneModule
     * @throws Exception
     */
    public TgeneModule getTgeneModule(String pModulecode) throws Exception {
        return TgeneModule.find(PersistenceHelper.getEntityManager(), pModulecode);
    }

    /**
     * Metodo que obtiene datos de un registro del producto.
     * 
     * @param pModulecode Codigo de modulo a obtener datos de la base.
     * @param pProductcode Codigo de producto a obtener datos de la base.
     * @return TgeneProduct
     * @throws Exception
     */
    public TgeneProduct getTgeneProduct(String pModulecode, String pProductcode) throws Exception {
        return TgeneProduct.find(PersistenceHelper.getEntityManager(), pModulecode, pProductcode);
    }

    /**
     * Metodo que obtiene datos de un registro del subproducto.
     * 
     * @param pModulecode Codigo de modulo a obtener datos de la base.
     * @param pProductcode Codigo de producto a obtener datos de la base.
     * @param pSubproductcode Codigo de subproducto a obtener datos de la base.
     * @return TgeneSubProduct
     * @throws Exception
     */
    public TgeneSubProduct getTgeneSubProduct(String pModulecode, String pProductcode, String pSubproductcode) throws Exception {
        return TgeneSubProduct.find(PersistenceHelper.getEntityManager(), pModulecode, pProductcode, pSubproductcode);
    }

    /**
     * Metodo que devuelve un registro de la tabla TGENEACCOUNT
     * 
     * @param account Numero de la cuenta
     * @param company Compania a la que pertenece la cuenta
     * @param dateto Fecha de vigencia de la tarjeta
     * @return
     */
    public TgeneAccount getTgeneAccount(String account, Integer company, Timestamp dateto) throws Exception {
        return TgeneAccount.findByFechaVigenciaTarjeta(PersistenceHelper.getEntityManager(), account, company, dateto);
    }

    /**
     * Entrega una lista de excepciones de solicitud.
     * 
     * @param pSolicitudenumber Numero de solicitud.
     * @param pSolicitudesequence Secuencia interna de la solicitud.
     * @return List<TgeneSolicitudeExceptions>
     * @throws Exception
     */
    public List<TgeneSolicitudeExceptions> getTgeneSolicitudeExceptions(String pSolicitudenumber, Integer pSolicitudesequence) throws Exception {
        return TgeneSolicitudeExceptions.findBySolicitudeNumber(PersistenceHelper.getEntityManager(), pSolicitudenumber, pSolicitudesequence);
    }

    /**
     * Metodo que entrega una lista de datos requeridos de clientes por producto.
     * 
     * @param pModuleCode Codigo de modulo.
     * @param pProductCode Codigo de producto.
     * @param pSubproductCode Codigo de subproducto.
     * @param pPersontype Tipo de persona.
     * @return List<TgeneSubprodClientData>
     * @throws Exception
     */
    public List<TgeneSubprodClientData> getTgeneSubprodClientData(String pModuleCode, String pProductCode, String pSubproductCode,
            String pPersontype, String pRelationshipcode) throws Exception {
        return TgeneSubprodClientData.findByProduct(PersistenceHelper.getEntityManager(), pModuleCode, pProductCode, pSubproductCode, pPersontype,
                pRelationshipcode);
    }

    /**
     * Metodo que entrega una lista de datos activos requeridos de clientes por producto.
     * 
     * @param pModuleCode Codigo de modulo.
     * @param pProductCode Codigo de producto.
     * @param pSubproductCode Codigo de subproducto.
     * @param pPersontype Tipo de persona.
     * @return List<TgeneSubprodClientData>
     * @throws Exception
     */
    public List<TgeneSubprodClientData> getTgeneSubprodClientDataActive(String pModuleCode, String pProductCode, String pSubproductCode,
            String pPersontype, String pRelationshipcode) throws Exception {
        return TgeneSubprodClientData.findByProductActive(PersistenceHelper.getEntityManager(), pModuleCode, pProductCode, pSubproductCode,
                pPersontype, pRelationshipcode);
    }

    /**
     * Entrega una lista de clientes relacionados a la solicitud.
     * 
     * @param pSolicitudenumber Numero de solicitud.
     * @param pSolicitudesequence Secuencia interna de la solicitud.
     * @return List<TgeneSolicitudeRelationship>
     * @throws Exception
     */
    public List<TgeneSolicitudeRelationship> getTgeneSolicitudeRelationship(String pSolicitudenumber, Integer pSolicitudesequence) throws Exception {
        return TgeneSolicitudeRelationship.findBySolicitudeNumber(PersistenceHelper.getEntityManager(), pSolicitudenumber, pSolicitudesequence);
    }

    /**
     * Metodo que devuelve un objeto de tipo TgeneSolicitudeClientdata
     * 
     * @param solicitudnumber
     * @param solicitudsequence
     * @param title
     * @param personcode
     * @return
     * @throws Exception
     */
    public TgeneSolicitudeClientdata getTgeneSolicitudeClientdata(String solicitudnumber, Integer solicitudsequence, String title, Integer personcode)
            throws Exception {
        return TgeneSolicitudeClientdata.find(PersistenceHelper.getEntityManager(), solicitudnumber, solicitudsequence, title, personcode);
    }

    /**
     * Metodo que devuelve un objeto de tipo TgeneSolicitude
     * 
     * @param solicitudnumber
     * @param solicitudsequence
     * @return
     * @throws Exception
     */
    public TgeneSolicitude getTgeneSolicitude(String solicitudnumber, Integer solicitudsequence) throws Exception {
        return TgeneSolicitude.find(PersistenceHelper.getEntityManager(), solicitudnumber, solicitudsequence);
    }

    /**
     * Metodo que devuelve un objeto de tipo TgeneSubprodClientData
     * 
     * @param modulecode
     * @param productcode
     * @param subproductcode
     * @param persontype
     * @param relationshipcode
     * @param title
     * @return
     * @throws Exception
     */
    public TgeneSubprodClientData getTgeneSubprodClientData(String modulecode, String productcode, String subproductcode, String persontype,
            String relationshipcode, String title) throws Exception {
        return TgeneSubprodClientData.find(PersistenceHelper.getEntityManager(), modulecode, productcode, subproductcode, persontype,
                relationshipcode, title);
    }

    /**
     * Metodo que obtiene datos de un registro del subproducto.
     * 
     * @param pModulecode Codigo de modulo a obtener datos de la base.
     * @param pProductcode Codigo de producto a obtener datos de la base.
     * @param pSubproductcode Codigo de subproducto a obtener datos de la base.
     * @return TgeneSubProduct
     * @throws Exception
     */
    public TsafeUserDetail getTsafeUserDetail(String usercode) throws Exception {
        return TsafeUserDetail.findByUserCode(PersistenceHelper.getEntityManager(), usercode);
    }

    /**
     * Entrega un objeto con la calificacion a asociar a un prestamo, dado el tipo de credito, estatus operativo y el
     * numero de dias de vencida una operacion.
     * 
     * @param pCreditType Codigo de tipo de credito Consumo, Comercial.
     * @param pOperationStatus Cordo de estatus de operacion, Original, restructurada
     * @param pModuleCode Modulo al que pertenece el estado operativo.
     * @param processdate Fecha en la cual se realiza la calificacion.
     * @param expirationdate Fecha desde la cual esta vencido el credito.
     * @return TgeneScoreRank
     * @throws Exception
     */
    public TgeneScoreRank getTgeneScoreRank(String pCreditType, String pOperationStatus, String pModuleCode, Date processdate, Date expirationdate)
            throws Exception {
        APPDates datefrom = null;
        APPDates dateto = null;
        int days = 0; // Si la fvencimiento esta en el futuro, indica que el prestamo tiene la mejor calificacion.
        if (processdate.compareTo(expirationdate) >= 0) {
            dateto = new APPDates(processdate);
            datefrom = new APPDates(expirationdate);
            dateto.setBase(CalculationBase.B365365);
            days = dateto.substract(datefrom);
        }

        TgeneScoreRank obj = null;

        List<TgeneScoreRank> ldata = this.getTgeneScoreRank(pCreditType, pOperationStatus, pModuleCode);

        if ((ldata == null) || ldata.isEmpty()) {
            return obj;
        }
        obj = ldata.get(0);
        for (TgeneScoreRank object : ldata) {
            if ((days >= object.getDaysfrom()) && (days <= object.getDaysto())) {
                obj = object;
                break;
            }
        }
        return obj;
    }

    /**
     * Entrega una lista con la calificacion a asociar a un prestamo, dado el tipo de credito, estatus operativo y el
     * numero de dias de vencida una operacion.
     * 
     * @param pCreditType Codigo de tipo de credito Consumo, Comercial.
     * @param pOperationStatus Cordo de estatus de operacion, Original, restructurada
     * @param pModuleCode Modulo al que pertenece el estado operativo.
     * @return List<TgeneScoreRank>
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public List<TgeneScoreRank> getTgeneScoreRank(String pCreditType, String pOperationStatus, String pModuleCode) throws Exception {
        List<TgeneScoreRank> ldata = null;
        String key = pCreditType + pOperationStatus + pModuleCode;
        CacheManager cm = CacheManager.getInstance();
        ldata = (List<TgeneScoreRank>) cm.getData("TgeneScoreRank", key);
        if (ldata == null) {
            Map<String, Object> mTgeneScoreRank = cm.getMapDefinition("TgeneScoreRank");
            ldata = TgeneScoreRank.find(PersistenceHelper.getEntityManager(), pCreditType, pOperationStatus, pModuleCode);
            mTgeneScoreRank.put(key, ldata);
            cm.putData("TgeneScoreRank", mTgeneScoreRank);
        }
        return ldata;
    }

    /**
     * Entrega un objeto con el porcentaje de provision de acuerdo a la calificacion tipo de credito.
     * 
     * @param pScoreScode Codigo de calificacion de cartera. A,B,C,D
     * @param pCreditType Codigo de tipo de credito, Consumo, COmercial.
     * @return TgenePercentScore
     * @throws Exception
     */
    public TgenePercentScore getTgenePercentScore(String pScoreScode, String pCreditType) throws Exception {
        TgenePercentScore obj = null;
        String key = pScoreScode + pCreditType;
        CacheManager cm = CacheManager.getInstance();
        obj = (TgenePercentScore) cm.getData("TgenePercentScore", key);
        if (obj == null) {
            Map<String, Object> mTgenePercentScore = cm.getMapDefinition("TgenePercentScore");
            TgenePercentScoreKey k = new TgenePercentScoreKey(pScoreScode, pCreditType, FormatDates.getDefaultExpiryTimestamp());
            obj = TgenePercentScore.find(PersistenceHelper.getEntityManager(), k);
            mTgenePercentScore.put(key, obj);
            cm.putData("TgenePercentScore", mTgenePercentScore);
        }
        return obj;
    }

    /**
     * Entrega una lista de cargos por subproducto.
     * 
     * @param pSolicitudenumber Numero de solicitud.
     * @param pSolicitudesequence Secuencia interna de la solicitud.
     * @return List<TgeneSolicitudeRelationship>
     * @throws Exception
     */
    public List<TgeneSubProductCharges> getTgeneSubProductChargesByCompany(Integer pCompany) throws Exception {
        return TgeneSubProductCharges.findByCompany(PersistenceHelper.getEntityManager(), pCompany);
    }

    /**
     * Entrega una lista de cargos por modulo.
     * 
     * @param pModuleCode
     * @return
     * @throws Exception
     */
    public List<TgeneSubProductCharges> getTgeneSubProductChargesByModule(String pModuleCode) throws Exception {
        return TgeneSubProductCharges.findByModule(PersistenceHelper.getEntityManager(), pModuleCode);
    }

    /**
     * Entrega una lista de cargos por modulo.
     * 
     * @param pModuleCode
     * @return
     * @throws Exception
     */
    public List<TgeneCharges> getTgeneChargesByModule(String pModuleCode) throws Exception {
        return TgeneCharges.findByModule(PersistenceHelper.getEntityManager(), pModuleCode);
    }

    /**
     * Metodo que entrega la descripcion del status de una garantia
     * 
     * @param pModuleCode
     * @param pStatuscode
     * @return
     * @throws Exception
     */
    public TgeneAccountStatus getTgeneAccountStatus(String pModuleCode, String pStatuscode) throws Exception {
        TgeneAccountStatus obj = null;
        String key = pModuleCode + Constant.SEPARATOR + pStatuscode;
        CacheManager cm = CacheManager.getInstance();
        obj = (TgeneAccountStatus) cm.getData("TgeneAccountStatus", key);
        if (obj == null) {
            Map<String, Object> mTgeneAccountStatus = cm.getMapDefinition("TgeneAccountStatus");
            TgeneAccountStatusKey keyp = new TgeneAccountStatusKey(pModuleCode, pStatuscode);
            obj = TgeneAccountStatus.find(PersistenceHelper.getEntityManager(), keyp);
            mTgeneAccountStatus.put(key, obj);
            cm.putData("TgeneAccountStatus", (Object) mTgeneAccountStatus);
        }
        return obj;
    }

}
