package com.fp.viaticos.rules.save.solicitud;

import java.math.BigDecimal;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

import javax.persistence.Query;

import com.fp.common.helper.Constant;
import com.fp.dto.rules.TransactionRule;
import com.fp.dto.save.SaveRequest;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.pviaticos.param.ViaParametros;
import com.fp.persistence.pviaticos.solicitud.ViaSolicitud;
import com.fp.viaticos.rules.enums.EnumCodigos;
import com.fp.viaticos.rules.exception.ViaticosException;
/**
 * Clase que valida las fechas de la solicitud
 * @author BPTWPA
 * @version 2.1
 */
public class ValidaFeriados extends TransactionRule {

	private static final long serialVersionUID = 1L;
	
	/**
     * Milisegundos
     */
    private static final long MILISEGUNDOS = 24 * 60 * 60 * 1000;
    
	/**
	 * M&eacute;todo que ejecuta el proceso de mantenimiento/control
	 */
	@Override
	public SaveRequest normalProcess(SaveRequest pSaveRequest) throws Exception {
		
		if (Constant.ifYes((String) pSaveRequest.get("isnew")) || pSaveRequest.get("csolicitud") != null) {
            return pSaveRequest;
        }
        
		String csolicitud = (String)pSaveRequest.get("csolicitud");
		
		ViaSolicitud viasolicitud = (ViaSolicitud) pSaveRequest.getSaveBeanModifiedObject("SOLICITUD");
        if (viasolicitud == null) {
            return pSaveRequest;
        }
        if(csolicitud!=null && viasolicitud.equals(csolicitud)){
        	return pSaveRequest;
        }
        this.validateDates(viasolicitud);
        this.validateViatico(viasolicitud);
        this.validateSolicitude(viasolicitud);
		return pSaveRequest;
	}

	/**
     * Validaci&acute;n de fechas de la solicitud
     * @param solicitud
     */
    public void validateSolicitude(ViaSolicitud solicitud) throws Exception{
    	
    	String firstYear = this.getYear(solicitud.getFec_ini_viatico());
    	String secondYear = this.getYear(solicitud.getFec_fin_viatico());
    	String firstDate = this.getDate(solicitud.getFec_ini_viatico());
    	String secondDate = this.getDate(solicitud.getFec_fin_viatico());
    	
    	Query qry = PersistenceHelper.getEntityManager().createNativeQuery(ValidaFeriados.SQL);
    	qry.setParameter("firstYear", firstYear);
    	qry.setParameter("secondYear", secondYear);
    	qry.setParameter("firstDate", firstDate);
    	qry.setParameter("secondDate", secondDate);
    	
    	List feriados = qry.getResultList();
    	
    	if(!feriados.isEmpty()){
    		throw new ViaticosException("VIA-0003", "EXISTEN D\u00cdAS FERIADOS PARA EL PERIODO: {0} / {1}", this.getDate(solicitud.getFec_ini_viatico()), this.getDate(solicitud.getFec_fin_viatico()));
    	}
    }
    
    /**
     * Validaci&acute;n de fechas de la solicitud
     * @param solicitud
     */
    public void validateViatico(ViaSolicitud solicitud) throws Exception{
    	
    	String firstDate = this.getDate(solicitud.getFec_ini_viatico());
    	
    	Query qry = PersistenceHelper.getEntityManager().createNativeQuery(ValidaFeriados.SQL_SOL);
    	qry.setParameter("firstDate", firstDate);
    	qry.setParameter("initTime", solicitud.getFec_hora_inicio());
    	qry.setParameter("codEmployee", solicitud.getCod_empleado());
    	
    	List solicitudes = qry.getResultList();
    	
    	if(!solicitudes.isEmpty()){
    		throw new ViaticosException("VIA-0004", "YA EXISTE UNA SOLICITUD INGRESADA PARA EL PERIODO: {0} / {1}", this.getDate(solicitud.getFec_ini_viatico()), this.getDate(solicitud.getFec_fin_viatico()));
    	}
    }
    
    /**
     * Val&iacute;da las fechas de comisi&oacute;n
     * @param solicitud ViaSolicitud
     * @throws Exception
     */
    private void validateDates(ViaSolicitud solicitud) throws Exception{
		
		long dias = (solicitud.getFec_fin_viatico().getTime() - solicitud.getFec_ini_viatico().getTime()) / ValidaFeriados.MILISEGUNDOS;

		ViaParametros parametroDias = ViaParametros.find(PersistenceHelper.getEntityManager(), EnumCodigos.VIA_03.getCodigo());
		
		if(parametroDias==null){
			throw new ViaticosException("VIA-0005", "PAR\u00c1METRO DE N\u00daMERO M\u00c1XIMO DE D\u00CDAS NO ENCONTRADO");
		}
		
		if(parametroDias.getNum_valor().compareTo(new BigDecimal(dias)) < 0){
			throw new ViaticosException("VIA-0006", "HA EXCEDIDO EL N\u00daMERO DE D\u00cdAS PERMITIDOS PARA EL VI\u00cdTICO");
		}
		
		if(this.obtieneDia(solicitud.getFec_ini_viatico())==1 || this.obtieneDia(solicitud.getFec_ini_viatico())==7){
			ViaParametros param = ViaParametros.find(PersistenceHelper.getEntityManager(), EnumCodigos.VIA_04.getCodigo());
			if(param.getTex_valor().equals("N")){
				throw new ViaticosException("VIA-0008", "NO PUEDE REGISTRAR UN FIN DE SEMANA COMO SALIDA DEL VI\u00cdTICO {0}",this.getDate(solicitud.getFec_ini_viatico()));
			}
		}
		
		if(this.obtieneDia(solicitud.getFec_fin_viatico())==7){
			ViaParametros param = ViaParametros.find(PersistenceHelper.getEntityManager(), EnumCodigos.VIA_05.getCodigo());
			if(param.getTex_valor().equals("N")){
				throw new ViaticosException("VIA-0009", "NO PUEDE REGISTRAR UN FIN DE SEMANA COMO LLEGADA DEL VI\u00cdTICO {0}",this.getDate(solicitud.getFec_fin_viatico()));
			}
		}
		
		for(int i=0; i <= dias;i++){
			Date fecha = this.agregarDias(solicitud.getFec_ini_viatico(), i);
			int dia = this.obtieneDia(fecha);
			if(i == 0 && ( dia == 1 || dia == 7)){
				continue;
			}
			if(i == dias && dia == 1){
				throw new ViaticosException("VIA-0009", "NO PUEDE REGISTRAR UN FIN DE SEMANA COMO LLEGADA DEL VI\u00cdTICO {0}",this.getDate(solicitud.getFec_fin_viatico()));
			}
			if(dia == 1 || dia == 7){
				throw new ViaticosException("VIA-0007", "EXISTEn FINES DE SEMANA EN EN EL PERIODO SELECIONADO {0} / {1}",this.getDate(solicitud.getFec_ini_viatico()), this.getDate(solicitud.getFec_fin_viatico()));
			}
		}
	}
    
	@Override
	public SaveRequest reverseProcess(SaveRequest pSaveRequest) throws Exception {
		// TODO Auto-generated method stub
		return pSaveRequest;
	}
	
	/**
	 * Entrega el anio
	 * @param date Fecha
	 * @return year
	 */
	private String getYear(Date date){
		Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return String.valueOf(calendar.get(Calendar.YEAR));
	}
	
	/**
	 * Obtiene la fecha en string
	 * @param date
	 * @return
	 */
	private String getDate(Date date){
		SimpleDateFormat formato = new SimpleDateFormat("dd-MM-yyyy", new Locale("es", "ES"));
        return formato.format(date);
	}
	/**
     * Agrega dias a una fecha
     */
    private Date agregarDias(Date fecha, int dias) {
        Calendar calendario = Calendar.getInstance();
        calendario.setTime(fecha);
        calendario.add(Calendar.DATE, dias);
        return new Date(calendario.getTime().getTime());
    }
    /**
     * obriene el dia de la semana
     */
    private Integer obtieneDia(Date fecha) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(fecha);
        return cal.get(Calendar.DAY_OF_WEEK);
    }
	/**
	 * Sql del esquema SRM para los dias feriados
	 */
	private static String SQL = "select FEC_DIA from SRM.SRM_DIAS_FERIADOS "
			+ "where (to_char(FEC_DIA, 'yyyy') = :firstYear or to_char(FEC_DIA, 'yyyy') = :secondYear) "
			+ "AND FEC_DIA BETWEEN TO_DATE(:firstDate, 'dd-MM-yyyy') AND TO_DATE(:secondDate, 'dd-MM-yyyy')";
	
	/**
	 * Sql para obtener las solicitudes ingresadas
	 */
	private static String SQL_SOL = "SELECT DISTINCT(SOL.COD_SOLICITUD) FROM VIA.VIA_SOLICITUD SOL "
			+ "WHERE SOL.COD_ESTADO NOT IN ('SAN') AND SOL.COD_EMPLEADO = :codEmployee "
			+ "AND SOL.FEC_FIN_VIATICO >= TO_DATE( :firstDate, 'dd-MM-yyyy') and SOL.FEC_HORA_FIN >= :initTime ";
}
