package com.ejie.ad74a.util;


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ejie.ad74a.exception.Ad74aException;

/**
 * Agrupa metodos de acceso al api batch de PIF.
 * 
 * @author JBHG
 */
public class Ad74aUtilPif {

    private static Logger logger = LoggerFactory.getLogger(Ad74aUtilPif.class);

    /**
     * Operaciones definidas con PIF
     * 
     * @author JBHG
     *
     */
    private enum OPERATIONS {
        GET("get"), PUT("put"), INFO("info"), DELETE("delete"), LIST("list"), DELETE_DIRECTORY(
                "deleted"), GET_DIRECTORY("getd");
        String operation;

        private OPERATIONS(String op) {
            this.operation = op;
        }

    }

    /**
     * Ruta al api batch de PIF.
     */
    private static String pifApiPath = null;

    /**
     * 
     *
     */
    private Ad74aUtilPif() {
    }
    
    public static void init(String pifApiCommandPath) {
    	pifApiPath = pifApiCommandPath;
    }

    /*
     * Obtiene el path del .sh de pif. Si no está definido, lo coge de properties.
     */
    private static String getPifApiPath() {
        return Ad74aUtilPif.pifApiPath;
    }

    /**
     * Descarga el fichero de PIF a disco, especificando el path del fichero donde se quiere
     * guardar. Devuelve bean con los datos del fichero.
     * 
     * @param appCodeLogin
     * @param pifPath
     * @param diskPathTo
     * @return path en disco
     * @throws IOException
     * @throws Ad74aException
     */
    public static AttachmentBeanPIF get(String appCodeLogin, String pifPath, String diskPathTo)
            throws Ad74aException {
        try {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "get. appCodeLogin=" + appCodeLogin + ", pifPath=" + pifPath + ", diskPathTo=" + diskPathTo);
            }
            // Crea directorio destino, si no existiese
//Files.createDirectories(Paths.get(UtilFiles.getFolder(diskPathTo)));

            // Invocacion al metodo GET (recupera bytes)
            StringBuilder execString = new StringBuilder(getPifApiPath());
            execString.append(" ");
            execString.append(appCodeLogin).append(" ");
            execString.append(OPERATIONS.GET.operation).append(" ");
            execString.append(pifPath).append(" ");
            execString.append(diskPathTo);
            Ad74aUtilPif.executeCommand(execString.toString());
            // Invocacion al metodo INFO (recupera metadatos)
            execString.setLength(0);
            execString.trimToSize();
            execString.append(getPifApiPath()).append(" ");
            execString.append(appCodeLogin).append(" ");
            execString.append(OPERATIONS.INFO.operation).append(" ");
            execString.append(pifPath);
            String resultado = Ad74aUtilPif.executeCommand(execString.toString());

            // Junta ambos resultados en un bean.
            AttachmentBeanPIF beanPIF = new AttachmentBeanPIF(resultado);
            FileInputStream fileInputStream = new FileInputStream(diskPathTo);
            beanPIF.setContentInputStream(fileInputStream);
            beanPIF.setDiskPath(diskPathTo);
            return beanPIF;
        } catch (IOException e) {
        	logger.error(Ad74aUtilPif.class.getName() + ".get-->" + Ad74aException.escribirStackTrace(e));
			throw new Ad74aException(Ad74aUtilPif.class.getName() + ".get-->" + Ad74aException.escribirStackTrace(e));
        }
    }

    /**
     * Descarga los ficheros de un directorio de PIF a disco, especificando el path del directorio
     * donde se quiere guardar. Devuelve lista de los ficheros descargados.
     * 
     * @param appCodeLogin
     * @param pifPath
     * @param diskPathTo
     * @param deletePif
     * @return paths en disco
     * @throws IOException
     * @throws Ad74aException
     */
    public static List<AttachmentBeanPIF> getd(String appCodeLogin, String pifPath, String diskPathTo,
            Boolean deletePif) throws Ad74aException {
        try {
            if (logger.isTraceEnabled()) {
                logger.trace("getd. appCodeLogin=" + appCodeLogin + ", pifPath=" + pifPath + ", diskPathTo="
                        + diskPathTo + ", deletePif=" + deletePif);
            }
            // Crea directorio destino, si no existiese
            Files.createDirectories(Paths.get(diskPathTo));
            // Obtiene lista de archivos que se van a descargar
            List<AttachmentBeanPIF> result = list(appCodeLogin, pifPath);

            // Invocacion al metodo GET_DIRECTORY (recupera bytes)
            StringBuilder execString = new StringBuilder(getPifApiPath());
            execString.append(" ");
            execString.append(appCodeLogin).append(" ");
            execString.append(OPERATIONS.GET_DIRECTORY.operation).append(" ");
            execString.append(pifPath).append(" ");
            execString.append(diskPathTo).append(" ");
            if (deletePif != null) {
                execString.append(deletePif.booleanValue());
            }
            Ad74aUtilPif.executeCommand(execString.toString());
            for (AttachmentBeanPIF bean : result) {
                bean.setDiskPath(diskPathTo + "/" + bean.getName());
            }
            return result;
        } catch (IOException e) {
        	logger.error(Ad74aUtilPif.class.getName() + ".getd-->" + Ad74aException.escribirStackTrace(e));
			throw new Ad74aException(Ad74aUtilPif.class.getName() + ".getd-->" + Ad74aException.escribirStackTrace(e));
        }
    }

    /**
     * Escribe un fichero de disco a PIF.
     * 
     * @param appCodeLogin
     *            String
     * @param diskPathFrom
     *            String
     * @param pifPathTo
     *            String
     * 
     * @return path en PIF
     * 
     * @throws Exception
     *             e
     */
    public static final AttachmentBeanPIF put(String appCodeLogin, String diskPathFrom, String pifPathTo)
            throws Ad74aException {
        if (logger.isTraceEnabled()) {
            logger.trace(
                    "put. appCodeLogin=" + appCodeLogin + ", pathFrom=" + diskPathFrom + ", pifPathTo=" + pifPathTo);
        }
        StringBuilder execString = new StringBuilder(getPifApiPath());
        execString.append(" ");
        execString.append(appCodeLogin).append(" ");
        execString.append(OPERATIONS.PUT.operation).append(" ");
        execString.append(diskPathFrom).append(" ");
        execString.append(pifPathTo).append(" ");
        execString.append(true).append(" ");// preserveName
        execString.append("1296000");// 15 dias
        // Ejecutamos el script
        String resultado = Ad74aUtilPif.executeCommand(execString.toString());
        if (!StringUtils.isEmpty(resultado)) {
            return new AttachmentBeanPIF(resultado);
        }
        // [JBHG] Definir excepcion propia...
        logger.error(Ad74aUtilPif.class.getName() + ".getd() Error al escribir el fichero " + pifPathTo + " en PIF-->");
		throw new Ad74aException(Ad74aUtilPif.class.getName() + Ad74aUtilPif.class.getName() + ".getd() Error al escribir el fichero " + pifPathTo + " en PIF-->");

    }

    /**
     * Devuelve la lista de ficheros de una carpeta en PIF.
     * 
     * @param appCodeLogin
     *            String
     * @param pifPathToList
     *            String
     * @return List
     * @throws IOException
     *             e
     * @throws Ad74aException
     *             e
     */
    public static List<AttachmentBeanPIF> list(String appCodeLogin, String pifPathToList) throws Ad74aException {
        if (logger.isTraceEnabled()) {
            logger.trace("list. appCodeLogin=" + appCodeLogin + ", pifPathToList=" + pifPathToList);
        }
        List<AttachmentBeanPIF> result = new ArrayList<AttachmentBeanPIF>();
        // Invocacion al metodo LIST (recupera bytes)
        StringBuilder execString = new StringBuilder(getPifApiPath());
        execString.append(" ");
        execString.append(appCodeLogin).append(" ");
        execString.append(OPERATIONS.LIST.operation).append(" ");
        execString.append(pifPathToList);
        String resultado;
        resultado = Ad74aUtilPif.executeCommand(execString.toString());
        if (!StringUtils.isEmpty(resultado)) {
            String[] files = resultado.split("\n");
            for (String file : files) {
                result.add(new AttachmentBeanPIF(file));
            }
        }
        return result;
    }

    /**
     * Borra un fichero de PIF especificando login de aplicacion.
     * 
     * @param appCodeLogin
     *            String
     * @param pifPathToRemove
     *            String
     * @return List
     * @throws IOException
     *             e
     * @throws Ad74aException
     *             e
     */
    public static void delete(String appCodeLogin, String pifPathToRemove) throws Ad74aException {
        if (logger.isTraceEnabled()) {
            logger.trace("delete. appCodeLogin=" + appCodeLogin + ", pifPathToRemove=" + pifPathToRemove);
        }
        // Invocacion al metodo delete
        StringBuilder execString = new StringBuilder(getPifApiPath());
        execString.append(" ");
        execString.append(appCodeLogin).append(" ");
        execString.append(OPERATIONS.DELETE.operation).append(" ");
        execString.append(pifPathToRemove);
        Ad74aUtilPif.executeCommand(execString.toString());
    }

    /**
     * Borra de una ruta PIF todos los ficheros, especificando login de aplicacion.
     * 
     * @param appCodeLogin
     *            String
     * @param pifPathToRemove
     *            String
     * @return List
     * @throws IOException
     *             e
     * @throws Ad74aException
     *             e
     */
    public static void deleted(String appCodeLogin, String pifPathToRemove) throws Ad74aException {
        if (logger.isTraceEnabled()) {
            logger.trace("deleted. appCodeLogin=" + appCodeLogin + ", pifPathToRemove=" + pifPathToRemove);
        }
        // Invocacion al metodo delete
        StringBuilder execString = new StringBuilder(getPifApiPath());
        execString.append(" ");
        execString.append(appCodeLogin).append(" ");
        execString.append(OPERATIONS.DELETE_DIRECTORY.operation).append(" ");
        execString.append(pifPathToRemove);
        Ad74aUtilPif.executeCommand(execString.toString());
    }

    /**
     * Ejecuta comandos en linea, devuelve un String con el resultado de la cadena
     * 
     * @param command String
     * 
     * @return String
     * 
     * @throws IOException e
     * 
     * @throws Ad74aException e
     **/
    private static String executeCommand(String command) throws Ad74aException {
        StringBuilder output = new StringBuilder();
        Process p;
        try {
        	logger.info("ExecuteCommand_PIF-->" + command);
            p = Runtime.getRuntime().exec(command);
            //p.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
 
            String line;
            while ((line = reader.readLine()) != null) {
                if (output.length() > 0) {
                    output.append("\n");
                }
                output.append(line);
            }
            if(output.length()==0) {
                StringBuilder outputError = new StringBuilder();
                BufferedReader readerError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
                while ((line = readerError.readLine()) != null) {
                    if (outputError.length() > 0) {
                        outputError.append("\n");
                    }
                    outputError.append(line);
                }
                if(logger.isWarnEnabled()) {
                    logger.warn(String.valueOf(outputError));
                }
                
                if ((line = readerError.readLine()) != null) {
                	throw new Ad74aException(Ad74aUtilPif.class.getName() + ".executeCommand-->" + String.valueOf(outputError));
				}
            }
            return output.toString();
        } catch (IOException e) {
			throw new Ad74aException(Ad74aUtilPif.class.getName() + ".executeCommand-->" + Ad74aException.escribirStackTrace(e));
		}catch (Exception e) {
			logger.error("ExecuteCommand_PIF-->" + e.getMessage());
			return "";
		}
    }
    
    /**
     * Metodo que recupera los ficheros de un directorio PIF y los deja en el directorio destino en el servidor
     * 
     * @param pathPIF String
     * 
     * @param pathDestino Strin
     * 
     * @return String
     * 
     * @throws Ad74aException e
     * 
     **/
    
    public static void recuperaFicherosRecepPIF(String login, String pathPIF, String pathDestino) throws Ad74aException {
    	
    	//Primero se recuperan todos los ficheros del directorio PIF
    	List<AttachmentBeanPIF> listFicheros = Ad74aUtilPif.list(login, pathPIF);
    	//Recorre la lista de ficheros que hay en el directorio PIF
    	for (int i = 0; i < listFicheros.size(); i++) {
			//Se extre el path del objeto.
    		String pathFichero = listFicheros.get(i).getPath();
    		String nombreFichero = listFicheros.get(i).getName();
    		
    		//Diferencia los paths de Windows de Unix/Linux
    		if (pathDestino.contains("/")) {
    			nombreFichero = "/" + nombreFichero;
			}else {
				nombreFichero = "\\" + nombreFichero;
			}
    		
    		//Se baja el archivo al directorio destino del servidor.
    		Ad74aUtilPif.get(login, pathFichero, pathDestino + nombreFichero);
    		
		}
    }
}