
package datos;

import encapsuladores.CabeceraFactura;
import encapsuladores.LineaFactura;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public class FacturaPDF {
    public void generarPDF(Object[] datosFactura) throws IOException{              
                  
            DecimalFormat[] decimalFormat = new FormatosNumericos().getFormatosNumericos();
            
            CabeceraFactura cabeceraFactura = (CabeceraFactura)datosFactura[1];
            List<LineaFactura> listaLineasFactura = (List<LineaFactura>) datosFactura[2];        
            
            String[] textosEspecificosPagina = {"EL CLIENTE", "LA EMPRESA", "LA ADMINISTRACION"};
            
            PDDocument pDDocument = new PDDocument();            
         // protegerDocumento(pDDocument, cabeceraFactura);   // Transferimos la referencia a cabeceraFactura
                                                              // para que el password de acceso al documento
                                                              // sea el NIF del cliente : 12345-X
            PDPage pDPage;
            PDPageContentStream pDPageContentStream;
            
            for (int contadorPaginas = 1; contadorPaginas<= textosEspecificosPagina.length; contadorPaginas++){
                pDPage = new PDPage();
                pDDocument.addPage(pDPage);
                pDPageContentStream = new PDPageContentStream(pDDocument, pDPage);
                escribirCuerpoFactura(pDDocument, pDPageContentStream, decimalFormat, cabeceraFactura, listaLineasFactura, contadorPaginas, textosEspecificosPagina);                                 
                pDPageContentStream.close();
            }
            
            pDDocument.save((String)datosFactura[0]);
            pDDocument.close();    
    }
    
    private void escribirCuerpoFactura(PDDocument pDDocument, PDPageContentStream pDPageContentStream, DecimalFormat[] decimalFormat, CabeceraFactura cabeceraFactura, List<LineaFactura> listaLineasFactura, int contadorPaginas, String[] textosEspecificosPagina) throws IOException{
                   //  LOGO          
            PDImageXObject imagen = PDImageXObject.createFromFile("imgs/logo_grua.jpg", pDDocument);          
            pDPageContentStream.drawImage(imagen, 50, 690);           
                   //  DATOS EMPRESA
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD_ITALIC, 9, 125, 720, "MATERIALES DE CONSTRUCCION, S.L.");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ITALIC, 8, 125, 710, "AV./Montes Universales, 58");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ITALIC, 8, 125, 700, "Pol.Industrial METROPOLITANO");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ITALIC, 8, 125, 690, "MADRID");
            
            escribirLinea(pDPageContentStream, 30, 670, 580, 670);
                   //  DATOS CLIENTE                   
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 9, 450, 650, "CLIENTE :");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 450, 635, cabeceraFactura.getNombreCliente());
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 450, 625, "NIF : "+cabeceraFactura.getNIFCliente());
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 450, 615, cabeceraFactura.getDireccionCliente());
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 450, 605, cabeceraFactura.getPoblacionCliente());
                   //  DATOS FACTURA           
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 50, 625, "FACTURA NÚM.");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 118, 625, String.format("%1$9d", cabeceraFactura.getNumeroFactura()));
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 50, 610, "Fecha factura:");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_ROMAN, 8, 118, 610, new java.text.SimpleDateFormat("dd-MM-yyyy").format(cabeceraFactura.getFechaFactura()));            
                   //  CUADRO COLUMNAS LINEAS            
            escribirLinea(pDPageContentStream, 50, 570, 560, 570);
            escribirLinea(pDPageContentStream, 50, 555, 560, 555);
            escribirLinea(pDPageContentStream, 50, 570, 50, 555);
            escribirLinea(pDPageContentStream, 560, 570, 560, 555);
            escribirLinea(pDPageContentStream, 120, 570, 120, 555);
            escribirLinea(pDPageContentStream, 330, 570, 330, 555);
            escribirLinea(pDPageContentStream, 410, 570, 410, 555);
            escribirLinea(pDPageContentStream, 480, 570, 480, 555);           
                   //  NOMBRES COLUMNAS LINEAS            
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 55, 560, "REFERENCIA");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 150, 560, "DESCRIPCIÓN");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 355, 560, "PRECIO");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 425, 560, "UNIDADES");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 500, 560, "IMPORTE");
                   //  LINEAS             
            LineaFactura lineaFactura;
            int numeroLineas = listaLineasFactura.size();                
            for (int i=0; i<numeroLineas; i++){         
               escribirLinea(pDPageContentStream, 50, 555-(15*(i+1)), 560, 555-(15*(i+1)));
               escribirLinea(pDPageContentStream, 50, 570-(15*(i+1)), 50, 555-(15*(i+1)));               
               escribirLinea(pDPageContentStream, 120, 570-(15*(i+1)), 120, 555-(15*(i+1)));
               escribirLinea(pDPageContentStream, 330, 570-(15*(i+1)), 330, 555-(15*(i+1)));
               escribirLinea(pDPageContentStream, 410, 570-(15*(i+1)), 410, 555-(15*(i+1)));
               escribirLinea(pDPageContentStream, 480, 570-(15*(i+1)), 480, 555-(15*(i+1)));
               escribirLinea(pDPageContentStream, 560, 570-(15*(i+1)), 560, 555-(15*(i+1)));
               lineaFactura = listaLineasFactura.get(i);
                      //  Para una tabulación correcta de columnas numéricas es necesario utilizar como font : PDType1Font.COURIER 
               escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 60, 560-(15*(i+1)), lineaFactura.getReferenciaArticulo());
               escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 130, 560-(15*(i+1)), lineaFactura.getDescripcion());
               escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 340, 560-(15*(i+1)), String.format("%11s",decimalFormat[2].format(lineaFactura.getPrecioUnitario())));
               escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 410, 560-(15*(i+1)), String.format("%12s",decimalFormat[0].format(lineaFactura.getUnidades())));
               escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 480, 560-(15*(i+1)), String.format("%15s",decimalFormat[3].format(lineaFactura.getImporteLinea())));
               
            }
                   //  PIE FACTURA            
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 430, 560-(15*numeroLineas)-25, "BRUTO :");       
            escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 480, 560-(15*numeroLineas)-25, String.format("%15s",decimalFormat[3].format(cabeceraFactura.getBrutoFactura(listaLineasFactura))));
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 360, 560-(15*numeroLineas)-45, "IVA :"); 
            escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 370, 560-(15*numeroLineas)-45, String.format("%5s",decimalFormat[1].format(cabeceraFactura.getIVA()))+"%");
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 430, 560-(15*numeroLineas)-45, "IMPORTE IVA :");       
            escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 480, 560-(15*numeroLineas)-45, String.format("%15s",decimalFormat[3].format(cabeceraFactura.getImporteIVA(listaLineasFactura))));
            escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 8, 430, 560-(15*numeroLineas)-65, "LIQUIDO :");       
            escribirTexto(pDPageContentStream, PDType1Font.COURIER, 8, 480, 560-(15*numeroLineas)-65, String.format("%15s",decimalFormat[3].format(cabeceraFactura.getLiquidoFactura(listaLineasFactura))));  
                   //  PIE FACTURA  
        escribirTexto(pDPageContentStream, PDType1Font.TIMES_BOLD, 5, 260, 50, "EJEMPLAR PARA "+textosEspecificosPagina[contadorPaginas-1]);          
    }
    
    private void escribirTexto(PDPageContentStream pDPageContentStream, PDFont pdFont, float sizeFuente, float inicioH, float inicioV,  String texto) throws IOException {
               
        pDPageContentStream.beginText();   
        pDPageContentStream.setFont(pdFont, sizeFuente);
        pDPageContentStream.newLineAtOffset(inicioH, inicioV);
        pDPageContentStream.showText(texto);
        pDPageContentStream.endText();
    }
       
    private void escribirLinea(PDPageContentStream pDPageContentStream, float inicioH, float inicioV, float finH, float finV) throws IOException {
        pDPageContentStream.moveTo(inicioH, inicioV);
        pDPageContentStream.lineTo(finH, finV);
        pDPageContentStream.stroke();
    }        
    
    private void protegerDocumento(PDDocument pDDocument, CabeceraFactura cabeceraFactura) throws IOException{
            AccessPermission accessPermission = new AccessPermission();
            accessPermission.setCanPrint(false);
            accessPermission.setCanPrintDegraded(false);
            accessPermission.setCanExtractContent(false);
            accessPermission.setCanExtractForAccessibility(false);
            accessPermission.setCanFillInForm(true);
            accessPermission.setCanModify(false);
            accessPermission.setReadOnly();
                                        //                                                  PASSWORD      PASSWORD
                                        //                                                  PROPIETARIO   USUARIO: será el NIF del cliente              
            StandardProtectionPolicy standardProtectionPolicy = new StandardProtectionPolicy("12345", cabeceraFactura.getNIFCliente(), accessPermission);
            standardProtectionPolicy.setEncryptionKeyLength(128);
            standardProtectionPolicy.setPreferAES(true);
            standardProtectionPolicy.setPermissions(accessPermission);
            pDDocument.protect(standardProtectionPolicy);               
    }
}
