package com.ejie.ab04b.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ejie.ab04b.constantes.ConstantesDocumentos;
import com.ejie.ab04b.constantes.ConstantesNum;
import com.ejie.ab04b.dao.ComunicacionAperturaCustomDao;
import com.ejie.ab04b.dao.ComunicacionPrlDao;
import com.ejie.ab04b.exception.AB04BException;
import com.ejie.ab04b.model.ComunicacionApertura;
import com.ejie.ab04b.model.ComunicacionPrl;
import com.ejie.ab04b.util.ws.documentgenerator.Ab04bDocumentGeneratorWS;

/**
 * GeneracionEtiquetasImpl generated by UDA, 11-Jan-2017 12:23:08.
 * 
 * @author UDA
 */

@Service(value = "generacionEtiquetasImpl")
public class GeneracionEtiquetasImpl implements GeneracionEtiquetasService {

	// private HashMap<String, String> datoS = new HashMap<String, String>();
	private HashMap<String, List<HashMap<String, String>>> datosListaMap = new HashMap<String, List<HashMap<String, String>>>();

	@Autowired()
	private ComunicacionAperturaCustomDao comunicacionAperturaCustomDao;

	@Autowired()
	private ComunicacionPrlDao comunicacionPrlDao;
	
//	private static final Logger LOGGER = LoggerFactory.getLogger(GeneracionEtiquetasImpl.class);

	/**
 * Devuelve un InputStream con el documento pdf.
 * 
 *  listadoFolderNumber
 *            String[]
 *  Inputstream
 *
 * @param listadoFolderNumber the listado folder number
 * @return the etiquetas
 * @throws AB04BException the AB 04 B exception
 */
	public InputStream getEtiquetas(String[] listadoFolderNumber)
			throws AB04BException {
		try {
			InputStream inputStream = null;
			List<ComunicacionApertura> listadoAperturas = new ArrayList<ComunicacionApertura>();
			ComunicacionApertura apertura = null;
			ComunicacionPrl os = null;
			List<ComunicacionApertura> aux = new ArrayList<ComunicacionApertura>();
			String tipo = null;

			for (int i = 0; i < listadoFolderNumber.length; i++) {
				tipo = listadoFolderNumber[i].split("~")[0];
				if (ConstantesDocumentos.COMUNICA_OS2.equals(tipo)
						|| ConstantesDocumentos.COMUNICA_OS2OS3.equals(tipo)
						|| ConstantesDocumentos.REQ_APERTURA.equals(tipo)) {
					apertura = new ComunicacionApertura();

					String territorio = listadoFolderNumber[i].split("~")[1];
					String anio = listadoFolderNumber[i].split("~")[ConstantesNum.NUM_2];
					String numero = listadoFolderNumber[i].split("~")[ConstantesNum.NUM_3];

					apertura.setTerape056(territorio);
					apertura.setAnoape056(anio);
					apertura.setNumape056(new Long(numero));

					aux = (List<ComunicacionApertura>) this.comunicacionAperturaCustomDao
							.obtenerDatosEtiquetas(apertura, false);
				} else if (ConstantesDocumentos.REQ_OS2.equals(tipo)
						|| ConstantesDocumentos.REQ_OS3.equals(tipo)) {
					os = new ComunicacionPrl();

					String territorio = listadoFolderNumber[i].split("~")[1];
					String anio = listadoFolderNumber[i].split("~")[ConstantesNum.NUM_2];
					String numero = listadoFolderNumber[i].split("~")[ConstantesNum.NUM_3];

					os.setTeros(territorio);
					os.setAnoos(anio);
					os.setNumos(Integer.parseInt(numero));

					aux = (List<ComunicacionApertura>) this.comunicacionPrlDao
							.obtenerDatosEtiquetas(os, false);

				}
				listadoAperturas.add(aux.get(0));
			}
			inputStream = this.pintarEtiquetas(listadoAperturas);

			return inputStream;
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

	/**
	 * Devuelve un InputStream con el documento pdf.
	 * 
	 *  listadoAperturas
	 *            List<ComunicacionApertura>
	 *  Inputstream
	 *
	 * @param listadoAperturas the listado aperturas
	 * @return the input stream
	 * @throws AB04BException the AB 04 B exception
	 */
	public InputStream pintarEtiquetas(
			List<ComunicacionApertura> listadoAperturas) throws AB04BException {
		try {
			List<HashMap<String, String>> hmDatos = new ArrayList<HashMap<String, String>>();
			HashMap<String, String> hmDatosFila = new HashMap<String, String>();
			StringBuffer domicilio = new StringBuffer();

			int columnas = 0;
			if (listadoAperturas.size() > 0) {
				// this.datoS.put("mensajeVacio1", "");
				for (int i = 0; i < listadoAperturas.size(); i++) {
					if (columnas == 0) {
						hmDatosFila = new HashMap<String, String>();
					}
					domicilio = new StringBuffer();
					if (listadoAperturas.get(i).getDatosNotificacion()
							.getDatosLocalizacion().getCalle067() != null) {
						domicilio.append(
								listadoAperturas.get(i).getDatosNotificacion()
										.getDatosLocalizacion().getCalle067())
								.append(" ");
					}

					if (listadoAperturas.get(i).getDatosNotificacion()
							.getDatosLocalizacion().getPortal067() != null) {
						domicilio.append(
								listadoAperturas.get(i).getDatosNotificacion()
										.getDatosLocalizacion().getPortal067())
								.append(" ");
					}

					if (listadoAperturas.get(i).getDatosNotificacion()
							.getDatosLocalizacion().getPiso067() != null) {
						domicilio.append(
								listadoAperturas.get(i).getDatosNotificacion()
										.getDatosLocalizacion().getPiso067())
								.append(" ");
					}

					if (listadoAperturas.get(i).getDatosNotificacion()
							.getDatosLocalizacion().getPuerta067() != null) {
						domicilio.append(
								listadoAperturas.get(i).getDatosNotificacion()
										.getDatosLocalizacion().getPuerta067())
								.append(" ");
					}

					if (columnas > 0) {
						hmDatosFila
								.put("razonsocial1",
										listadoAperturas.get(i).getNomemp056() != null ? listadoAperturas
												.get(i).getNomemp056() : "");

						hmDatosFila.put("domicilio1", domicilio.toString());

						hmDatosFila
								.put("localidad1",
										listadoAperturas.get(i)
												.getDatosNotificacion()
												.getDatosLocalizacion()
												.getLocalidad()
												.getDescripcion() != null ? listadoAperturas
												.get(i).getDatosNotificacion()
												.getDatosLocalizacion()
												.getLocalidad()
												.getDescripcion()
												: "");

						hmDatosFila.put("codpostal1", listadoAperturas.get(i)
								.getDatosNotificacion().getDatosLocalizacion()
								.getCodpostal067() != null ? listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getCodpostal067() : "");

						hmDatosFila.put("nommunicipio1", listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getMunicipio()
								.getDescripcion() != null ? listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getMunicipio()
								.getDescripcion() : "");

						hmDatosFila.put("nomprovincia1", listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getProvincia()
								.getDescripcion() != null ? listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getProvincia()
								.getDescripcion() : "");
					} else {
						hmDatosFila
								.put("razonsocial",
										listadoAperturas.get(i).getNomemp056() != null ? listadoAperturas
												.get(i).getNomemp056() : "");

						hmDatosFila.put("domicilio", domicilio.toString());

						hmDatosFila
								.put("localidad",
										listadoAperturas.get(i)
												.getDatosNotificacion()
												.getDatosLocalizacion()
												.getLocalidad()
												.getDescripcion() != null ? listadoAperturas
												.get(i).getDatosNotificacion()
												.getDatosLocalizacion()
												.getLocalidad()
												.getDescripcion()
												: "");

						hmDatosFila.put("codpostal", listadoAperturas.get(i)
								.getDatosNotificacion().getDatosLocalizacion()
								.getCodpostal067() != null ? listadoAperturas
								.get(i).getDatosNotificacion()
								.getDatosLocalizacion().getCodpostal067() : "");

						hmDatosFila
								.put("nommunicipio",
										listadoAperturas.get(i)
												.getDatosNotificacion()
												.getDatosLocalizacion()
												.getMunicipio()
												.getDescripcion() != null ? listadoAperturas
												.get(i).getDatosNotificacion()
												.getDatosLocalizacion()
												.getMunicipio()
												.getDescripcion()
												: "");

						hmDatosFila
								.put("nomprovincia",
										listadoAperturas.get(i)
												.getDatosNotificacion()
												.getDatosLocalizacion()
												.getProvincia()
												.getDescripcion() != null ? listadoAperturas
												.get(i).getDatosNotificacion()
												.getDatosLocalizacion()
												.getProvincia()
												.getDescripcion()
												: "");
					}

					columnas++;
					if (columnas > 1) {
						hmDatos.add(hmDatosFila);
						columnas = 0;
					}

				}
			}
			if (columnas > 0) {
				// Si ha acabado y es impar el último lo quitamos
				if (listadoAperturas.size() % ConstantesNum.NUM_2 != 0) {
					hmDatosFila.put("razonsocial1", "");
					hmDatosFila.put("domicilio1", "");
					hmDatosFila.put("localidad1", "");
					hmDatosFila.put("codpostal1", "");
					hmDatosFila.put("nommunicipio1", "");
					hmDatosFila.put("nomprovincia1", "");
				}
				hmDatos.add(hmDatosFila);
			}
			this.datosListaMap.put("registro", hmDatos);

			return this.createXML();
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

	/**
	 * Crea un xml para cada uno de los informes.
	 * 
	 *  InputStream
	 *
	 * @return the input stream
	 * @throws Exception             e
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public InputStream createXML() throws Exception {

		// Obtener la plantilla RTF
		FileInputStream fileInput = null;
		InputStream streamPlantilla = null;
		try{
			File file = new File(ConstantesDocumentos.PLANTILLA_ETIQUTAS_DIR);
			byte[] bFile = new byte[(int) file.length()];
			fileInput = new FileInputStream(file);
			fileInput.read(bFile);
			streamPlantilla = new ByteArrayInputStream(bFile);
				
			DocumentBuilderFactory documentFactory = DocumentBuilderFactory
					.newInstance();

			DocumentBuilder documentBuilder = documentFactory
					.newDocumentBuilder();

			DOMImplementation domImpl = documentBuilder.getDOMImplementation();
			Document doc = domImpl.createDocument("", "RTFTemplate", null);

			Element RTFTemplate = doc.getDocumentElement();

			RTFTemplate.setAttribute("xmlns:xsi",
					"http://www.w3.org/2001/XMLSchema-instance");
			RTFTemplate.setAttribute("xsi:noNamespaceSchemaLocation",
					"..\\file\\schemaRTFTemplate.xsd");

			Element RTFTemplateItems = doc.createElement("RTFTemplateItems");
			RTFTemplate.appendChild(RTFTemplateItems);

			// Datos de tipo String
			// Iterator iter = this.datoS.entrySet().iterator();
			Map.Entry e;
			// while (iter.hasNext()) {
			// e = (Map.Entry) iter.next();
			// GeneracionEtiquetasImpl.crearItemString(doc,
			// e.getKey().toString(),
			// e.getValue() != null ? e.getValue().toString() : "",
			// RTFTemplateItems);
			//
			// }
			// Datos de tipo ListMap
			Iterator iter = this.datosListaMap.entrySet().iterator();
			while (iter.hasNext()) {
				e = (Map.Entry) iter.next();
				List<HashMap<String, String>> lstGenMap = (ArrayList) e
						.getValue();
				GeneracionEtiquetasImpl.crearItemListMap(doc, lstGenMap, e
						.getKey().toString(), RTFTemplateItems);
			}
			TransformerFactory transformerFactory = TransformerFactory
					.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource domSource = new DOMSource(doc); // pasos = "8";
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			StreamResult streamResult = new StreamResult(bos);
			transformer.transform(domSource, streamResult);

			InputStream datosXML = new ByteArrayInputStream(bos.toByteArray());

			Ab04bDocumentGeneratorWS documentGenerator = new Ab04bDocumentGeneratorWS();
			return documentGenerator.generateDocument(
					datosXML, streamPlantilla);
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}finally{
			fileInput.close();
			streamPlantilla.close();
		}

	}

	/**
	 * Crear item list map.
	 * 
	 *  doc
	 *            Document
	 *  hmDatos
	 *            List
	 *  etiquetaPadre
	 *            String
	 *  RTFTemplateItems
	 *            Element
	 *
	 * @param doc the doc
	 * @param hmDatos the hm datos
	 * @param etiquetaPadre the etiqueta padre
	 * @param RTFTemplateItems the RTF template items
	 */
	@SuppressWarnings(value = "rawtypes")
	private static void crearItemListMap(Document doc,
			List<HashMap<String, String>> hmDatos, String etiquetaPadre,
			Element RTFTemplateItems) {

		Element RTFTemplateItem = doc.createElement("RTFTemplateItem");
		RTFTemplateItem.setAttribute("tipo", "ListMap");
		RTFTemplateItem.setAttribute("etiqueta", etiquetaPadre);
		RTFTemplateItems.appendChild(RTFTemplateItem);
		Element items = doc.createElement("items");
		RTFTemplateItem.appendChild(items);

		// Ahora hay que crear un elemento item por cada fila
		if (hmDatos != null) {
			for (int i = 0; i < hmDatos.size(); i++) {
				Map<String, String> dato = null;
				dato = hmDatos.get(i);
				Element item = doc.createElement("item");
				items.appendChild(item);
				Element items2 = doc.createElement("items");
				item.appendChild(items2);
				// Ahora, un elemento item por cada hashmap
				Iterator iter = dato.entrySet().iterator();
				Map.Entry e;
				while (iter.hasNext()) {
					e = (Map.Entry) iter.next();
					Element itemHijo = doc.createElement("item");
					itemHijo.setAttribute("etiqueta", e.getKey().toString());
					itemHijo.setTextContent(e.getValue().toString());
					items2.appendChild(itemHijo);
				}
			}
		}
	}

	/**
	 * Crear item string.
	 * 
	 *  doc
	 *            Document
	 *  etiqueta
	 *            String
	 *  valor
	 *            String
	 *  RTFTemplateItems
	 *            Element
	 *
	 * @param doc the doc
	 * @param etiqueta the etiqueta
	 * @param valor the valor
	 * @param RTFTemplateItems the RTF template items
	 */
	public static void crearItemString(Document doc, String etiqueta,
			String valor, Element RTFTemplateItems) {

		Element RTFTemplateItem = doc.createElement("RTFTemplateItem");
		RTFTemplateItem.setAttribute("tipo", "String");
		RTFTemplateItem.setAttribute("etiqueta", etiqueta);
		RTFTemplateItems.appendChild(RTFTemplateItem);
		Element items = doc.createElement("items");
		RTFTemplateItem.appendChild(items);
		Element item = doc.createElement("item");
		item.setTextContent(valor);
		items.appendChild(item);
	}
}
