package com.fp.persistence.commondb.helper;

import java.sql.Date;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.persistence.EntityManager;

import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;

import com.fp.common.exception.CommonException;
import com.fp.common.helper.Constant;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.exception.CommondbException;

public final class FormatDates {

    /** Intancia Singleton */
    private static FormatDates cache = null;

    /** Almacena el formato yyyy-MM-dd HH:mm:ss */
    private SimpleDateFormat vDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /** Almacena el formato yyyy-MM-dd */
    private SimpleDateFormat vDate = new SimpleDateFormat("yyyy-MM-dd");;

    /** Almacena el formato yyyy-MM-dd HH:mm:ss.SSS */
    private SimpleDateFormat vTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    /** Almacena el formato HH:mm:ss */
    private SimpleDateFormat vTime = new SimpleDateFormat("mm:ss.SSS");

    /** Almacena el formato HH:mm:ss */
    private SimpleDateFormat vTimeInseconds = new SimpleDateFormat("ss.SSS");

    /* Crea una Instancia de FormatDates */
    private FormatDates() {
    }

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

    /**
     * Obtiene el Formateador para el Transporte de Fechas: formato yyyy-MM-dd
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getTimeInSeconds() {
        if (vTimeInseconds == null) {
            vTimeInseconds = new SimpleDateFormat("ss.SSS");
        }
        return vTimeInseconds;
    }

    /**
     * Obtiene el Formateador para el Transporte de Fechas: formato yyyy-MM-dd
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getTransportDateFormat() {
        if (vDate == null) {
            vDate = new SimpleDateFormat("yyyy-MM-dd");
        }
        return vDate;
    }

    /**
     * Obtiene el Formateador para el Transporte de Timestamp: formato yyyy-MM-dd HH:mm:ss
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getTransportDatetimeFormat() {
        if (vDateTime == null) {
            vDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
        return vDateTime;

    }

    /**
     * Obtiene el formateador de Timestamps para su transaporte en String: formato yyyy-MM-dd HH:mm:ss.SSS
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getTransportTimestampFormat() {
        if (vTimestamp == null) {
            vTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        }
        return vTimestamp;
    }

    /**
     * Obtiene el formateador de Horas para su transaporte en String: formato HH:mm
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getHourSecondsFormat() {
        return new SimpleDateFormat("HH:mm");
    }

    /**
     * Obtiene el formateador de Horas para su transaporte en String: formato HH:mm:ss
     * 
     * @return SimpleDateFormat
     */
    public SimpleDateFormat getTimeFormat() {
        return new SimpleDateFormat("HH:mm:ss");
    }

    /**
     * Obtiene el formateador de un conteo de tiempo en String
     * 
     * @return SimpleDateFormat.
     */
    public SimpleDateFormat getTimeCountFormat() {
        if (vTime == null) {
            vTime = new SimpleDateFormat("mm:ss.SSS");
        }
        return vTime;
    }

    /**
     * Enterga el timestamp de la base de datos.
     * 
     * @return Timestamp
     * @throws CommonException
     * @throws HibernateException
     */
    public Timestamp getDataBaseTimestamp() throws HibernateException, CommondbException, Exception {
        Timestamp timestamp = null;
        String dialect = Constant.getDialect(PersistenceHelper.getEntityManager());
        String sql = "select CURRENT_TIMESTAMP as timestamp";//ANTES ORACLE: "SELECT systimestamp as timestamp FROM dual  ";
        if (dialect.compareTo("org.hibernate.dialect.SybaseDialect") == 0) {
            sql = "select CURRENT_TIMESTAMP as timestamp";//ANTES ORACLE: "select getDate() as timestamp ";
        }
        if (dialect.compareTo("org.hibernate.dialect.InformixDialect") == 0) {
            sql = "select CURRENT_TIMESTAMP as timestamp";
        }

        SQLQuery q = PersistenceHelper.getSession().createSQLQuery(sql);

        q.addScalar("timestamp", new org.hibernate.type.TimestampType());
        timestamp = (Timestamp) q.uniqueResult();
        GregorianCalendar gc = new GregorianCalendar();
        gc.setTimeInMillis(timestamp.getTime());
        if (gc.get(Calendar.MILLISECOND) == 0) {
            GregorianCalendar gc1 = new GregorianCalendar();
            gc1.setTimeInMillis(System.currentTimeMillis());
            gc.set(Calendar.MILLISECOND, gc1.get(Calendar.MILLISECOND));
            timestamp = new Timestamp(gc.getTimeInMillis());
        }
        return timestamp;
    }

    /**
     * Enterga el timestamp de la base de datos.
     * 
     * @return Timestamp
     * @throws CommonException
     * @throws HibernateException
     */
    public Timestamp getDataBaseTimestamp(EntityManager pEntityManager) throws HibernateException, CommondbException, Exception {
        Timestamp timestamp = null;
        String dialect = Constant.getDialect(pEntityManager);
        String sql = "select CURRENT_TIMESTAMP as timestamp";//ANTES ORACLE: "SELECT systimestamp as timestamp FROM dual  ";
        if (dialect.compareTo("org.hibernate.dialect.SybaseDialect") == 0) {
            sql = "select CURRENT_TIMESTAMP as timestamp ";//ANTES ORACLE: "select getDate() as timestamp ";
        }
        if (dialect.compareTo("org.hibernate.dialect.InformixDialect") == 0) {
            sql = "select CURRENT_TIMESTAMP as timestamp";
        }
        SQLQuery q = ((Session) pEntityManager.getDelegate()).createSQLQuery(sql);
        q.addScalar("timestamp", new org.hibernate.type.TimestampType());
        timestamp = (Timestamp) q.uniqueResult();
        return timestamp;
    }

    /**
     * Enterga el timestamp de la base de datos.
     * 
     * @return Date
     * @throws CommonException
     * @throws HibernateException
     */
    public Date getDataBaseDate() throws HibernateException, CommondbException {
        Date timestamp = null;//
        SQLQuery q = PersistenceHelper.getSession().createSQLQuery("select localtimestamp  as timestamp"); /**antes con oracle: SELECT sysdate as timestamp FROM dual*/
        q.addScalar("timestamp", new org.hibernate.type.DateType());
        timestamp = (Date) q.uniqueResult();
        return timestamp;
    }

    /**
     * Formatea una fecha para ser empleada como campo de particionamiento en una Tabla
     * 
     * @param pDate Fecha de Referencia.
     * @return String Fecha con el formato yyyyMM
     * @throws Exception
     */
    public static String getPartition(Date pDate) throws Exception {
        return Constant.getPartition(pDate);
    }

    /**
     * Formatea una fecha para ser empleada como campo de particionamiento en una Tabla
     * 
     * @param pDate Fecha de Referencia.
     * @return String Fecha con el formato yyyyMM
     * @throws Exception
     */
    public static String getPartition(Timestamp pDate) throws Exception {
        return Constant.getPartition(pDate);
    }

    /**
     * Entrega el la particion default de caducidad de registros.
     * 
     * @return Particion con el formato yyyyMM
     * @throws Exception
     */
    public static String getDefaultPartition() throws Exception {
        return "299912";
    }

    /**
     * Devuelve la fecha hasta default de 2999-12-31
     * 
     * @return Fecha hasta 2999-12-31
     * @throws Exception
     */
    public static Timestamp getDefaultExpiryTimestamp() throws Exception {
        return Constant.getDefaultExpiryTimestamp();
    }

    /**
     * Devuelve la fecha hasta default de 2999-12-31
     * 
     * @return Fecha hasta 2999-12-31
     * @throws Exception
     */
    public static java.sql.Date getDefaultExpiryDate() throws Exception {
        return Constant.getDefaultExpiryDate();
    }

}
