/*
 * Validador.java
 *
 * Created on 14 de marzo de 2007, 11:42 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.fidufosyga.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import com.csvreader.CsvReader;
import com.csvreader.CsvWriter;
import com.fidufosyga.context.Context;
import com.fidufosyga.exception.CancelarException;
import com.fidufosyga.exception.GeneralException;
import com.fidufosyga.rules.*;
import com.fidufosyga.xml.XMLRulesLoader;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

//inclui 16112023
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
//
/**
 * 
 * @author 
 */

public class Validador {

	/** Creates a new instance of Validador */
    public Validador() {
    }
//inclui 16112023 Clave encriptación archivo
private static final String SECRET_KEY = "EncriptadoADRES1"; //
//	
    public static final String ENTIDADES = "ENTIDADES_TODAS";

    public static EstadisticasBean validar() throws CancelarException,GeneralException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, Exception {
        String tipoArchivo = (String) Context.getContext().getAttribute(Context.TIPO_ARCHIVO);
        if (Context.getContext().getAttribute(tipoArchivo) == null) {
            try {
                XMLReader parser = XMLReaderFactory.createXMLReader();
                parser.setContentHandler(new XMLRulesLoader());
                parser.parse(System.getProperty("user.dir") + File.separator+ "xml" + File.separator + tipoArchivo + ".xml");
            } catch (IOException ex) {
                GeneralException e = new GeneralException("No se encuentra el archivo " + tipoArchivo + ".xml.",ex);
                throw (e);
            } catch (SAXException ex) {
                GeneralException e = new GeneralException("El archivo " + tipoArchivo+ ".xml esta corrupto. verifique la version de su aplicacion.",ex);
                throw (e);
            }
        }
        String destino = (String) Context.getContext().getAttribute(Context.DIRECTORIO_SALIDA);
        try {
            return validarCampos(tipoArchivo, destino);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Validador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    private static EstadisticasBean validarCampos(String tipoArchivo,String destino) throws GeneralException, CancelarException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, Exception {
        CsvReader csvData = null;
        AESUtilJava encriptador = new AESUtilJava();
        Charset charset = Charset.forName("ISO-8859-1");
        try {
            csvData = new CsvReader(Context.getContext().getAttribute(Context.ARCHIVO_ACTUAL).toString(),',',charset);
        } catch (FileNotFoundException e) {
            Context.getContext().addAttribute(Context.STATUS_VALIDACION,Context.STATUS_TERMINADO_ERROR);
            GeneralException ex = new GeneralException("No se encuentra el archivo a validar, verifique su presencia en el directorio seleccionado e intente de nuevo.",e);
            throw (ex);
        }
        csvData.setTrimWhitespace(false);
        String nombreArchivo = ((File) Context.getContext().getAttribute(Context.ARCHIVO_ACTUAL)).getName();
        System.out.println("nombreArchivo: " + nombreArchivo);
        CsvWriter csvWriterGlosado = new CsvWriter(destino+ nombreArchivo.substring(0, nombreArchivo.length() - 4)+ ".est", ',', charset);
        /*****************************************************************************/
        String nombreArchivoValidados = destino + nombreArchivo.substring(0, nombreArchivo.length() - 4) + ".val";
        CsvWriter csvWriterValidos = new CsvWriter(nombreArchivoValidados, ',', charset);
        /*****************************************************************************/
        csvWriterValidos.setEscapeMode(CsvWriter.ESCAPE_MODE_BACKSLASH);
        csvWriterGlosado.setEscapeMode(CsvWriter.ESCAPE_MODE_BACKSLASH);
        csvWriterGlosado.setUseTextQualifier(false);
        csvWriterValidos.setUseTextQualifier(false);
        EstadisticasBean estadisticas = new EstadisticasBean();
        int totalRegistros = 0;
        int registrosGlosados = 0;
        int registrosValidos = 0;
        long tiempoInicial = System.currentTimeMillis();
        try {	
            System.out.println("Tipó Archivo: " + tipoArchivo);
            ArchivoModel archivo = (ArchivoModel) Context.getContext().getAttribute(tipoArchivo);
            String tipoFormulario = (String) Context.getContext().getAttribute(Context.TIPO_FORMULARIO);
            FormularioModel formulario = (FormularioModel) Context.getContext().getAttribute(tipoFormulario);
            // int numeroArchivo = (Integer)
            // Context.getContext().getAttribute(Context.MODELO_ARCHIVO_ACTUAL);
            // ArchivoModel archivo = (ArchivoModel)
            // formulario.getArchivosValidar().get(numeroArchivo);
            System.out.println("Archivo: " + (ArchivoModel) Context.getContext().getAttribute(tipoArchivo));
            System.out.println("Ruta Archivo: " + Context.getContext().getAttribute(Context.ARCHIVO_ACTUAL).toString());
            archivo.setNombreArchivoEntrada(((File) Context.getContext().getAttribute(Context.ARCHIVO_ACTUAL)).toString());
            archivo.setNombreArchivoSalida(nombreArchivoValidados);
            formulario.getArchivosValidar().add(archivo);
            // Lista para almacenar registros 22112023
           List<String[]> registrosEncriptados = new ArrayList<>();
           List<String[]> registrosNoEncriptados = new ArrayList<>();//
            while (csvData.readRecord()){
                StringBuilder glosas = new StringBuilder("");
                // System.out.println("validandoInner");
                if (Context.STATUS_CANCELADO.equals(Context.getContext().getAttribute(Context.STATUS_VALIDACION))) {
                    throw new CancelarException("Cancelado por el usuario");
                }
                if (archivo.getLongitudCampos() != csvData.getValues().length) {
                    if (glosas.length() == 0)
                        glosas.append(((Properties) Context.getContext().getAttribute(Context.PROPERTIES)).getProperty(Constantes.GLOSA_COLUMNAS_INVALIDAS));
                }else{
                    for (int i = 0; i < csvData.getValues().length; i++){
                        for (int j = 0; j < (archivo.getCamposValidacion().get(i).getListaValidaciones()).size(); j++) {
                            Validable val = (archivo.getCamposValidacion().get(i).getListaValidaciones()).get(j);
                            boolean result = val.performValidation(csvData.getValues()[i],csvData.getValues(), nombreArchivo);
                            //System.out.println("Resultado Validacion: " + result);
                            if (result){
                                if (glosas.length() == 0){
                                    glosas.append(val.getGlosa());
                                }else{
                                    glosas.append(";" + val.getGlosa());
                                }
                            }
                        }
                    }
                }	
                if (glosas.length() > 0){
                    ArrayList<String> lista = new ArrayList<String>(Arrays.asList(csvData.getValues()));
                    lista.add(glosas.toString());
                    csvWriterGlosado.writeRecord(lista.toArray(new String[lista.size()]), true);
                    registrosGlosados++;
                    totalRegistros++; // Incrementar el contador total de registros
                }else{
                    //inclui 16112023 Encriptación de datos
                     boolean contieneN46 = csvData.getValues().length > 11 && csvData.getValues()[11].equals("N46");
                    if (contieneN46) {
                        int[] indicesCamposEncriptar = {13, 15, 16};
                        String[] registroEncriptado = csvData.getValues().clone(); // Crear una copia del registro actual
                    
                    for (int indiceCampo : indicesCamposEncriptar) {
                    if (indiceCampo >= 0 && indiceCampo < csvData.getValues().length) {
                        String valorCampo = registroEncriptado[indiceCampo];
                        byte[] campoEncriptado = null;                    
                                     
                    try {
                        Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                         SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), "AES");
                        aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);
                        campoEncriptado = aesCipher.doFinal(valorCampo.getBytes());
                        //System.out.println("Valor Campo Encriptado: " + Arrays.toString(campoEncriptado)); 
                    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException ex) {
                        Logger.getLogger(Validador.class.getName()).log(Level.SEVERE, null, ex);
                        
                    }
                     if (campoEncriptado != null) {
                         
                        String campoEncriptadoString = Base64.getEncoder().encodeToString(campoEncriptado);
                        //registroEncriptado[indiceCampo] = campoEncriptadoString; // Asignar el valor encriptado al campo correspondiente
                        String base64texto= encriptador.encryptAndEncode(valorCampo);
                        registroEncriptado[indiceCampo] = encriptador.base64ToHex(base64texto);
                        //System.out.println("Valor Campo Encriptado indice: " +registroEncriptado[indiceCampo]);
                        //System.out.println("Valor Campo Encriptado: " + campoEncriptadoString);
                    }
                }
            }

            // Agregar el registro encriptado 
            registrosEncriptados.add(registroEncriptado);
              } else {
            // Agregar el registro no encriptado 
            registrosNoEncriptados.add(csvData.getValues());
                }
            }
        
        }
            // Escribir los registros no encriptados directamente en csvValidos
            
            for (String[] registro : registrosNoEncriptados) {
                csvWriterValidos.writeRecord(registro, true);
                registrosValidos++;  
                totalRegistros++;
            }
         

            // Escribir los registros encriptados desde la lista al archivo csvValidos
            for (String[] registro : registrosEncriptados) {
                csvWriterValidos.writeRecord(registro, true);
                registrosValidos++;  
                totalRegistros++; // Incrementar el contador total de registros
            }
                          
                
            
            Context.getContext().addAttribute(Context.STATUS_VALIDACION,Context.STATUS_TERMINADO);
        } catch (CancelarException e) {
            Context.getContext().addAttribute(Context.STATUS_VALIDACION,Context.STATUS_TERMINADO_ERROR);
            throw (e);
        } catch (FileNotFoundException e) {
            Context.getContext().addAttribute(Context.STATUS_VALIDACION,Context.STATUS_TERMINADO_ERROR);
            GeneralException ex = new GeneralException("No se encuentra el archivo a validar, verifique su presencia en el directorio seleccionado e intente de nuevo.",e);
			throw (ex);
		} catch (IOException e) {
			Context.getContext().addAttribute(Context.STATUS_VALIDACION,
					Context.STATUS_TERMINADO_ERROR);
			GeneralException ex = new GeneralException(
					"Ocurrio un error validando el archivo, reinicie el programa. Si el problema persiste contacte a su proveedor.",
					e);
			throw (ex);
		}

		finally {
			csvWriterValidos.close();
			csvWriterGlosado.close();
			csvData.close();

		}

		estadisticas.setRegistrosGlosados(new Long(registrosGlosados));
		estadisticas.setRegistrosValidos(new Long(registrosValidos));
		estadisticas.setTotalRegistros(new Long(totalRegistros));
		estadisticas.setTiempoTranscurrido(new Integer((int) (System
				.currentTimeMillis() - tiempoInicial)));
		estadisticas.setDirectorioOut(destino);

		ArchivoModel archivo = (ArchivoModel) Context.getContext()
				.getAttribute(tipoArchivo);
		archivo.setEstadisticas(estadisticas);

		return estadisticas;

	}
	
	public static int ValidarNombreArchivo() throws CancelarException, GeneralException
	{
		String entidadArchivo = null;
		String codigoDepto = null;
		String codigoMunicipio = null;
		Integer mesArchivo = null;
		Integer annioArchivo = null;
		Pattern pattern = null;
		
		Properties defaultProps = new Properties();
		FileInputStream in;

		String nombreArchivo = ((File) Context.getContext().getAttribute(
				Context.ARCHIVO_ACTUAL)).getName().substring(0, ((File) Context.getContext().getAttribute(
						Context.ARCHIVO_ACTUAL)).getName().indexOf("."));
		
		String tipoArchivo = (String) Context.getContext().getAttribute(
				Context.TIPO_ARCHIVO).toString();
		
		if(tipoArchivo.equals("RARC"))
		{
			tipoArchivo = nombreArchivo.substring(6,10);
			entidadArchivo = nombreArchivo.substring(0,6);
			mesArchivo = Integer.parseInt(nombreArchivo.substring(12, 14));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(14, 18));
			
			pattern = Pattern.compile("^\\w{6}RARC\\d{8}$");
		}
		
		if(tipoArchivo.equals("RNEC"))
		{
			tipoArchivo = nombreArchivo.substring(0,4);
			entidadArchivo = nombreArchivo.substring(4,7);
			mesArchivo = Integer.parseInt(nombreArchivo.substring(9, 11));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(11, 15));
			
			pattern = Pattern.compile("^RNECMPS\\d{8}$");
			
		}
		
		if(tipoArchivo.equals("ELM"))
		{
			tipoArchivo = nombreArchivo.substring(0,3);
			entidadArchivo = null;
			mesArchivo = Integer.parseInt(nombreArchivo.substring(5, 7));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(7, 11));
			
			pattern = Pattern.compile("^ELM(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])(19|20)\\d\\d\\d\\d$");
			
		}
		
		if(tipoArchivo.equals("HFP"))
		{
			tipoArchivo = nombreArchivo.substring(0,3);
			entidadArchivo = null;
			mesArchivo = Integer.parseInt(nombreArchivo.substring(5, 7));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(7, 11));
			
			pattern = Pattern.compile("^HFP(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])(19|20)\\d\\d\\d\\d$");
		}
		
		if(tipoArchivo.equals("NS-Municipios"))
		{
			tipoArchivo = (String) Context.getContext().getAttribute(
					Context.TIPO_ARCHIVO).toString().substring(0, 2);
			
			codigoDepto = nombreArchivo.substring(2,4);
			mesArchivo = Integer.parseInt(nombreArchivo.substring(9, 11));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(11, 15));
			codigoMunicipio = nombreArchivo.substring(4,7);
			
			pattern = Pattern.compile("^NS\\d{5}\\d{8}$");
		
			tipoArchivo = "NS-Municipios";
			
		}
		if(!tipoArchivo.equals("HFP") && !tipoArchivo.equals("ELM") && !tipoArchivo.equals("NS-Municipios") && !tipoArchivo.equals("RARC") && !tipoArchivo.equals("RNEC"))
		{
			tipoArchivo = (String) Context.getContext().getAttribute(
					Context.TIPO_ARCHIVO).toString().substring(0, 2);
	
			entidadArchivo = nombreArchivo.substring(2,8);
			mesArchivo = Integer.parseInt(nombreArchivo.substring(10, 12));
			annioArchivo = Integer.parseInt(nombreArchivo.substring(12, 16));
			
			pattern = Pattern.compile("^"+tipoArchivo+"\\w{6}\\d{8}$");
		}

		System.out.println("TipoArchivo: " + tipoArchivo);
		System.out.println("EntidadArchivo: " + entidadArchivo);
		System.out.println("MesArchivo: " + mesArchivo);
		System.out.println("AnnioArchivo: " + annioArchivo);
		System.out.println("CodigoDepto: " + codigoDepto);
		System.out.println("CodigoMncpio: " + codigoMunicipio);

		
		Matcher matcher = pattern.matcher(nombreArchivo);

		boolean vaExRex = matcher.matches();

		if(!vaExRex)
			return 1;
		
		Calendar fecha = Calendar.getInstance();
		
		if(mesArchivo.equals(fecha.get(Calendar.MONTH)))
			return 2;

		if(!annioArchivo.equals(fecha.get(Calendar.YEAR)))
			return 3;
		
		if(entidadArchivo != null)
		{
			if (Context.getContext().getAttribute(ENTIDADES) == null) {
				try {
	
					in = new FileInputStream(System.getProperty("user.dir")
							+ File.separator + "entidades" + File.separator
							+ "entidadesTodas.properties");
					defaultProps.load(in);
					in.close();
					Context.getContext().addAttribute(ENTIDADES, defaultProps);
	
				} catch (FileNotFoundException e) {
					return 4;
				} catch (IOException e) {
					return 5;
				}
	
			}
			
			if (((Properties) Context.getContext().getAttribute(ENTIDADES))
					.getProperty(entidadArchivo) == null)
				return 6;
                        
                        if(entidadArchivo.equals("EPS006"))
                         return 6;
		}
                
		
		if(codigoDepto != null)
		{
			File file = new File(System.getProperty("user.dir") + File.separator
					+ "departamentos" + File.separator + codigoDepto
					+ ".properties");
			
			if (file.isFile())
				System.out.println("Existe el archivo: " + file);
			else
				return 7;

			try {
				in = new FileInputStream(System.getProperty("user.dir")
							+ File.separator + "departamentos" + File.separator
							+ codigoDepto + ".properties");
					defaultProps.load(in);
					in.close();
					Context.getContext()
							.addAttribute(codigoDepto, defaultProps);

			} catch (FileNotFoundException e) {
				return 8;
			} catch (IOException e) {
				return 9;
			}
			
			
			if (((Properties) Context.getContext().getAttribute(codigoDepto)).getProperty(codigoMunicipio) == null) 
				return 10;
		}

		return 0;
	}

}
