/**
 * 
 */
package com.ejie.aa21b.service;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.ejie.aa21b.ldap.SecurityHelpperException;
import com.ejie.aa21b.ldap.SecurityHelpperXLNets;
import com.ejie.aa21b.seguridad.Aa21bSeguridad;
import com.ejie.aa21b.util.Aa21bConstantes;
import com.ejie.w43df.pid.client.Exception_Exception;
import com.ejie.w43df.pid.client.W43DfAttribute;
import com.ejie.w43df.pid.client.W43DfContent;
import com.ejie.w43df.pid.client.W43DfCore;
import com.ejie.w43df.pid.client.W43DfDocument;
import com.ejie.w43df.pid.client.W43DfFormat;
import com.ejie.w43df.pid.client.W43DfGETContent;
import com.ejie.w43df.pid.client.W43DfGETDocument;
import com.ejie.w43df.pid.client.W43DfPIDInterface;
import com.ejie.w43df.pid.client.W43DfPIDService;
import com.ejie.w43df.pid.header.W43dfHeaderHandlerResolver;
import com.ejie.y31.factory.Y31JanoServiceAbstractFactory;
import com.ejie.y31.service.Y31JanoService;
import com.ejie.y31.vo.Y31AttachmentBean;

/**
 *  
 * 
 */
@Service(value = "Aa21bAccesoPIDService")
public class Aa21bAccesoPIDServiceImpl implements Aa21bAccesoPIDService {
	private static final Logger logger = LoggerFactory
			.getLogger(Aa21bAccesoPIDServiceImpl.class);
	@Autowired
	private Properties appConfiguration;
	private String token = null;

	/**
	 * inicializa el sistema
	 * 
	 * @return
	 * @throws MalformedURLException
	 */
	private W43DfPIDService inicializar() throws MalformedURLException {
		// N38APISesion n38Sesion = new N38APISesion();
		String codigoAplicacion = Aa21bConstantes.AA21B_CODAPP;
		logger.info("Inicializando PID service");
		try {
			if (token == null)
				token = crearTokenXlnet(codigoAplicacion);
			logger.info("token=" + token);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		W43dfHeaderHandlerResolver headerHandlerResolver = new W43dfHeaderHandlerResolver(
				token);

		URL wsldLocation = new URL(appConfiguration.getProperty("urlPid"));
		logger.info("URL PID=" + wsldLocation);
		W43DfPIDService PIDService = new W43DfPIDService(wsldLocation,
				new QName("com/ejie/documents/xml", "w43dfPIDService"));
		PIDService.setHandlerResolver(headerHandlerResolver);

		return PIDService;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.aa21b.service.Aa21bPIDService#saveNew(byte[],
	 * java.lang.String)
	 */
	@Override
	public String saveNew(byte[] data, String documentName, String extension)
			throws MalformedURLException {
		logger.info("SAVE New");
		logger.info("documentName=" + documentName);
		logger.info("extension=" + extension);
		String dataPath = "";
		logger.info("Subir al PIF");
		dataPath = this.subirAPIF(data, documentName, extension);
		if (!dataPath.equals("")) {
			logger.info("Subido al PIF=" + dataPath);
			W43DfPIDService PIDService = inicializar();
			W43DfPIDInterface documentsManager = PIDService.getW43DfPIDPort();
			W43DfDocument document = new W43DfDocument();
			// Doc. type
			document.setType(Aa21bConstantes.PIDGRUPO);
			// Core (establecer ACL)
			W43DfCore core = new W43DfCore();
			core.setAcl(Aa21bConstantes.PIDACL);
			document.setCore(core);
			// Contenido del documento.
			W43DfFormat format = new W43DfFormat();
			format.setExtension(extension);
			W43DfContent content = new W43DfContent();
			content.setFormat(format);
			// content.setBytes(data);
			content.setPath(dataPath);
			// content.setPath("/") --> PIF
			document.setContent(content);
			logger.info("Atributos PID FIN");
			// Attributes
			W43DfAttribute attribute = new W43DfAttribute();
			attribute.setKey("object_name");
			attribute.getValues().add(documentName);
			document.getAttributes().add(attribute);
			long initTimeMillis = System.currentTimeMillis();
			String documentId = "";
			try {
				documentId = documentsManager.addDocument(document);
				logger.info("Identificador del nuevo documento=" + documentId);
			} catch (Exception_Exception e) {
				logger.error(e.getMessage());
				StackTraceElement[] tr = e.getStackTrace();
				for (StackTraceElement aa : tr) {
					logger.error(aa.toString());
				}
			}
			long endTimeMillis = System.currentTimeMillis();
			logger.info("INTERNAL::: Stored document with ID '" + documentId
					+ "' in " + (endTimeMillis - initTimeMillis) + " mseconds.");
			return documentId;
		} else {

			logger.info("No subido al PIF");

			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ejie.W43Df.service.Aa21bPIDService#load(java.lang.String)
	 */
	@Override
	public byte[] load(String documentoId) throws MalformedURLException {
		logger.info("cargar fichero PID=" + documentoId);
		byte[] doc = null;
		W43DfPIDService PIDService = inicializar();

		W43DfPIDInterface documentsManager = PIDService.getW43DfPIDPort();

		W43DfGETContent content = new W43DfGETContent();
		String path = "/aa21b/";
		content.setPath(path);
		W43DfGETDocument getDocument = new W43DfGETDocument();
		getDocument.setContent(content);
		getDocument.setId(documentoId);

		long initTimeMillis = System.currentTimeMillis();
		W43DfDocument document = null;
		try {
			document = documentsManager.getDocument(getDocument);
			logger.info("Pasamos fichero del PID de aa66 a PIF" + path);
			document = documentsManager.getDocument(getDocument);
			path = document.getContent().getPath();
			logger.info("Fichero a cargar desde el PIF " + path);
			doc = this.bajarDesdePIF(path);
			logger.info("Fichero cargado");
		} catch (Exception_Exception e) {
			// TODO Auto-generated catch block
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}
		long endTimeMillis = System.currentTimeMillis();
		logger.info("INTERNAL::: Retrieved document with ID '" + documentoId
				+ "' in " + (endTimeMillis - initTimeMillis) + " mseconds.");

		return doc;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.ejie.aa21b.service.Aa21bPIDService#recuperarFormatosCMS(com.ejie.
	 * aa21b.pid.client.Aa21bPIDInterface)
	 */
	@Override
	public List<W43DfFormat> recuperarFormatosCMS(
			W43DfPIDInterface documentsManager) throws MalformedURLException {
		// TODO Auto-generated method stub
		return null;
	}

	/*
	 * Modifica el elemento con el id documentId, con los datos data y el
	 * formato formato
	 * 
	 * @see com.ejie.aa21b.service.Aa21bPIDService#modify(byte[],
	 * java.lang.String)
	 */
	@Override
	public void modify(byte[] data, String documentId, String formato)
			throws MalformedURLException {
		logger.info("modify: modificar documento del PID");
		logger.info("documentId=" + documentId);
		logger.info("formato=" + formato);
		W43DfPIDService PIDService = inicializar();
		logger.info("Subir al PIF");
		String dataPath = this.subirAPIF(data, "modificacion", formato);// Poner
																		// nombre
		if (!dataPath.equals("")) { // y
			// extensión
			logger.info("path=" + dataPath);
			W43DfPIDInterface documentsManager = PIDService.getW43DfPIDPort();
			W43DfFormat format = new W43DfFormat();
			format.setExtension(formato);
			W43DfContent content = new W43DfContent();
			content.setFormat(format);
			content.setPath(dataPath);
			W43DfDocument document = new W43DfDocument();
			document.setContent(content);
			document.setId(documentId);
			long initTimeMillis = System.currentTimeMillis();
			try {
				documentsManager.modifyDocument(document);

			} catch (Exception_Exception e) {
				// TODO Auto-generated catch block
				logger.error(e.getMessage());
				StackTraceElement[] tr = e.getStackTrace();
				for (StackTraceElement aa : tr) {
					logger.error(aa.toString());
				}
			}
			long endTimeMillis = System.currentTimeMillis();
			logger.info("INTERNAL::: Modified document with ID '" + documentId
					+ "' in " + (endTimeMillis - initTimeMillis) + " mseconds.");
		} else {
			logger.info("No subido al PIF");
		}

	}

	/*
	 * Borra del PID el elemento con el id documentId
	 * 
	 * @see com.ejie.aa21b.service.Aa21bPIDService#delete(java.lang.String)
	 */
	@Override
	public void delete(String documentId) throws MalformedURLException {
		logger.info("delete(Borrar documento del PIF)");
		logger.info("documentId=" + documentId);
		W43DfPIDService PIDService = inicializar();

		W43DfPIDInterface documentsManager = PIDService.getW43DfPIDPort();
		long initTimeMillis = System.currentTimeMillis();
		try {
			documentsManager.deleteDocument(documentId);
		} catch (Exception_Exception e) {
			// TODO Auto-generated catch block
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}
		long endTimeMillis = System.currentTimeMillis();
		logger.info("INTERNAL::: Deleted document with IDs '" + documentId
				+ "' in " + (endTimeMillis - initTimeMillis) + " mseconds.");
	}

	/*
	 * Borra del PID el elemento con el id documentId
	 * 
	 * @see com.ejie.aa21b.service.Aa21bPIDService#delete(java.lang.String)
	 */
	@Override
	public String copy(String documentId) throws MalformedURLException {
		logger.info("copy(copiar documento del PIF)");
		logger.info("documentId=" + documentId);
		W43DfPIDService PIDService = inicializar();

		W43DfPIDInterface documentsManager = PIDService.getW43DfPIDPort();
		long initTimeMillis = System.currentTimeMillis();
		String doc = "";

		W43DfGETContent content = new W43DfGETContent();
		String path = "/aa21b/";
		content.setPath(path);
		W43DfGETDocument getDocument = new W43DfGETDocument();
		getDocument.setContent(content);
		getDocument.setId(documentId);

		W43DfDocument document = null;
		try {
			document = documentsManager.getDocument(getDocument);
			logger.info("Pasamos fichero del PID de aa66 a PIF" + path);
			document = documentsManager.getDocument(getDocument);
			path = document.getContent().getPath();
			logger.info("Fichero a cargar desde el PIF " + path);

			doc = documentsManager.copyDocument(document);
		} catch (Exception_Exception e) {
			// TODO Auto-generated catch block
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}
		long endTimeMillis = System.currentTimeMillis();
		logger.info("INTERNAL::: Deleted document with IDs '" + documentId
				+ "' in " + (endTimeMillis - initTimeMillis) + " mseconds.");
		return doc;
	}

	protected String sendGetRequest(String urlStr) {
		String result = null;
		if (urlStr.startsWith("http://")) {
			try {
				URL url = new URL(urlStr);
				URLConnection connn = url.openConnection();
				BufferedReader rd = new BufferedReader(new InputStreamReader(
						connn.getInputStream()));
				StringBuffer sb = new StringBuffer();
				String line;
				while ((line = rd.readLine()) != null) {
					sb.append(line);
				}
				rd.close();
				result = sb.toString();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * Devuelve un token XLNEts de la aplicacion
	 */
	public Document crearXlnet(String cod) {
		Document d = null;
		try {
			d = stringToDom(crearTokenXlnet(cod));
		} catch (Exception e) {
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}
		return d;
	}

	// Metodo para crear el Token de sesión de xlnet para el acceso a PIF
	public String crearTokenXlnet(String cod) throws Exception {

		try {
			String urlXMLSesion = appConfiguration
					.getProperty("urlTokenXlnets") + cod;

			String urlFormateada = MessageFormat.format(urlXMLSesion,
					(Object[]) null);
			String xmlSesionString = sendGetRequest(urlFormateada);
			// System.out.println("XML sesion: \n" + xmlSesionString );
			return xmlSesionString;
		} catch (Exception e) {

		}
		return null;

	}

	public Document stringToDom(String xmlSource) throws SAXException,
			ParserConfigurationException, IOException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		return builder.parse(new InputSource(new StringReader(xmlSource)));
	}

	/**
	 * Sube al PIF el documento datos y devuelve el path del fichero
	 * 
	 * @param datos
	 * @return
	 */
	private String subirAPIF(byte[] plantilla, String nombre, String extension) {
		String to = "/w43df/" + nombre + System.currentTimeMillis() + "."
				+ extension;
		try {
			logger.info("Subir fichero con PIF=" + to + " Plantilla tamaño="
					+ plantilla.length);
			// obteniendo un objeto service
			Y31JanoService service = Y31JanoServiceAbstractFactory
					.getInstance();
			Document sesion = crearXlnet(Aa21bConstantes.AA21B_CODAPP);
			// Preparando los parámetros

			// FileInputStream file = new FileInputStream("c:/temp/dni.doc ");
			ByteArrayInputStream file = new ByteArrayInputStream(plantilla);

			boolean preserveName = false;
			Long expirationSecs = new Long(60 * 2); // 2 minutos

			// invocando el metodo
			Y31AttachmentBean resul = service.put(sesion, (InputStream) file,
					to, preserveName, expirationSecs);
			logger.info(" -->" + resul.getContentType());
			logger.info(" -->" + resul.getFileName());
			logger.info(" -->" + resul.getFilePath());
			logger.info(" -->" + resul.getSize());
			to = resul.getFilePath();
			file.close();
		} catch (Exception e) {
			to = "";
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}

		}

		return to;
	}

	/**
	 * Baja desde PIF el documento datos y devuelve el path del fichero
	 * 
	 * @param datos
	 * @return
	 */
	private byte[] bajarDesdePIF(String path) {
		byte[] to = null;
		try {
			logger.info("bajarDesdePIF=" + path);
			Document sesion = crearXlnet(Aa21bConstantes.AA21B_CODAPP);
			logger.info(sesion.toString());
			// obteniendo un objeto service
			Y31JanoService service = Y31JanoServiceAbstractFactory
					.getInstance();

			// Preparando los parámetros

			// FileInputStream file = new FileInputStream("c:/temp/dni.doc ");

			// boolean preserveName = false;
			// Long expirationSecs = new Long(60 * 2); // 2 minutos
			logger.info("leyendo");
			// invocando el metodo
			InputStream is = service.get(sesion, path);
			to = IOUtils.toByteArray(is);
			logger.info("terminado");

		} catch (Exception e) {

			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}

		}

		return to;
	}

	/**
	 * Baja desde PIF el documento datos y devuelve el path del fichero
	 * 
	 * @param datos
	 * @return
	 */
	@SuppressWarnings("unused")
	private byte[] bajarDesdePIFUsuario(String path) {
		byte[] to = null;
		try {
			logger.info("bajarDesdePIF=" + path);

			String usuario = "";
			try {
				usuario = new Aa21bSeguridad().getUsuario().getPersonaXLNET()
						.getCodigo();

			} catch (Exception e) {
				logger.error(" --> ERROR AL OBTENER EL USUARIO DE XLNETS");

			}
			/* Obtenemos el token de sesion del usuario que esta logueado */
			Document sesion = new SecurityHelpperXLNets().getItemSession();
			logger.info("Sesion de usuario de xlnets obtenida...");

			logger.info(sesion.toString());
			// obteniendo un objeto service
			Y31JanoService service = Y31JanoServiceAbstractFactory
					.getInstance();

			// Preparando los parÃ¡metros

			@SuppressWarnings("unused")
			boolean preserveName = false;
			Long expirationSecs = new Long(60 * 50); // 2 minutos
			logger.info("leyendo");
			// invocando el metodo
			InputStream is = service.get(sesion, path);

			to = IOUtils.toByteArray(is);
			logger.info("terminado");

		} catch (Exception e) {

			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}

		}

		return to;
	}

	public Y31AttachmentBean subirAPIFEdicion(byte[] datos, String nombre) {
		// Subimos el documento a una zona donde el pid tenga acceso luego
		// String to = "/w43df/apps/m56b/" + "plantilla.docx"; // Aquí poner u

		//

		logger.info(" -- > subirAPIFDocPorSiniestro <--");
		String usuario = "";

		try {
			usuario = new SecurityHelpperXLNets().getUsuario();

		} catch (SecurityHelpperException e) {
			logger.error(" --> ERROR AL OBTENER EL USUARIO DE XLNETS");

		}
		String to = "/user/" + usuario.toLowerCase() + "/apps/copy_aa21b/"
				+ nombre;

		Y31AttachmentBean resul = null;
		try {
			logger.info("Subir fichero con PIF=" + to);
			// obteniendo un objeto service
			logger.info("Obteniendo la variable servicio...");
			Y31JanoService service = Y31JanoServiceAbstractFactory
					.getInstance();

			logger.info("Obteniendo la variable sesion xml-xlnets");
			Document sesion = crearXlnet(Aa21bConstantes.AA21B_CODAPP);
			logger.info("sesion document : " + sesion.toString());

			// Preparando los parametros
			logger.info("Preparando los parametros");
			ByteArrayInputStream file = new ByteArrayInputStream(datos);

			boolean preserveName = false;
			Long expirationSecs = new Long(60 * 50); // 2 minutos

			// invocando el metodo
			logger.info("Invocando el metodo");
			resul = service.put(sesion, (InputStream) file, to, preserveName,
					expirationSecs);
			logger.info(" -->" + resul.getContentType());
			logger.info(" -->" + resul.getFileName());
			logger.info(" -->" + resul.getFilePath());
			logger.info(" -->" + resul.getSize());

			to = resul.getFilePath();

			file.close();
		} catch (Exception e) {
			// to = "";
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}

		}

		return resul;
	}

	/**
	 * Descarga el documento del pid, y lo pone en la zona de edición online del
	 * usuario conectado. Devuelve un aray primer elemento, la url de pif, y el
	 * segundo el path
	 */
	@Override
	public List<String> edicionOnline(String documentoId)
			throws MalformedURLException {
		// TODO Auto-generated method stub
		byte[] datos = load(documentoId);
		String path = documentoId + ".doc";
		Y31AttachmentBean res = subirAPIFEdicion(datos, path);
		ArrayList<String> resultado = new ArrayList<String>();
		resultado.add(res.getOnlineEditUrl());
		resultado.add(res.getFilePath());
		return resultado;
	}

	/**
	 * Descarga el documento del PIF del usuario y lo guarda en el PID
	 * 
	 * @param path
	 * @return
	 */
	public String subirFicheroEditado(String path) {
		byte[] datos = this.bajarDesdePIFUsuario(path);
		try {
			return this.saveNew(datos, System.currentTimeMillis() + "", "doc");
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}
		return "";
	}

	/**
	 * Descarga el documento del PIF del usuario y lo guarda en el PID en el
	 * documentId
	 * 
	 * @param path
	 * @return
	 */
	public void actualizarFicheroEditado(String path, String documentId) {
		byte[] datos = this.bajarDesdePIFUsuario(path);
		try {
			this.modify(datos, documentId, "doc");
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			logger.error(e.getMessage());
			StackTraceElement[] tr = e.getStackTrace();
			for (StackTraceElement aa : tr) {
				logger.error(aa.toString());
			}
		}

	}
}
