/*
 * This file is part of DebGen Biobank Software developed by ASTRID Research.
 * All rights reserved. Reproduction, modification, use or disclosure
 * to third parties without express authority is forbidden.
 *
 * Copyright ASTRID Research Inc., Hungary, 2009-2010.
 *
 * ASTRID Research
 * Headquaters: Csapo utca 42. Debrecen H-4029 HUNGARY
 * Phone: +36-52-533-173        Fax: +36-52-533-174
 * Web: http://www.astrid.hu    E-mail: info@astrid.hu
 *
 * Project name: DebGen Biobank Software project.
 * URLS:
 * Developers: Istvan Zoltan Nagy (istvan.nagy@astrid.hu)
 */
package hu.astrid.debgen.print;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPrintPage;
import hu.astrid.debgen.labelprint.domain.Label;
import hu.astrid.debgen.labelprint.printer.ZebraLabelPrinter;
import hu.astrid.debgen.labelprint.util.ReadFromXML;

import javax.print.PrintService;
import java.awt.print.*;
import java.io.*;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author inagy
 */
public class PrintController {

    private List<Label> lista = new ArrayList<Label>();
    private AppletPanel parent;
    /**
     * Boolean value to allow or deny label printing (useful, to cancel operation)
     */
    private boolean allowLabelprint = true;
    /**
     * Boolean value to allow or deny pdf printing (useful, to cancel operation)
     */
    private boolean allowPdfPrint = true;
    private int currentLabels = 0;
    private int totalLabels = 0;
    private String pdfPrinter;

    public String getPdfPrinter() {
        return pdfPrinter;
    }

    public void setPdfPrinter(String pdfPrinter) {
        this.pdfPrinter = pdfPrinter;
    }

    public boolean isAllowLabelprint() {
        return allowLabelprint;
    }

    public void setAllowLabelprint(boolean allowLabelprint) {
        this.allowLabelprint = allowLabelprint;
    }

    public boolean isAllowPdfPrint() {
        return allowPdfPrint;
    }

    public void setAllowPdfPrint(boolean allowPdfPrint) {
        this.allowPdfPrint = allowPdfPrint;
    }

    public List<Label> getLista() {
        return lista;
    }

    public void setLista(List<Label> lista) {
        this.lista = lista;
    }

    public AppletPanel getParent() {
        return parent;
    }

    public void setParent(AppletPanel parent) {
        this.parent = parent;
    }

    public PrintController(AppletPanel parent) {
        this.parent = parent;
    }

    public void printXml(URI xml) throws Exception {
        this.startLabels();
        this.allowLabelprint = true;
        this.currentLabels = 0;
        ZebraLabelPrinter printer = new ZebraLabelPrinter();
        this.lista = printer.createLabelListFromDocument(ReadFromXML.readFromXml(xml));
        this.totalLabels = 0;
        for (Label l : lista) {
            this.totalLabels += l.getCopies();
        }
        Thread.yield();
        for (Label l : lista) {
            int copies = l.getCopies();
            Label temp = Label.getInstance(l.getType());
            temp.setCodeValue(l.getCodeValue());
            for (int i = 0; i < copies; i++) {
                Thread.yield();
                if (this.allowLabelprint) {
                    this.setLabelName(temp.getCodeValue());
                    this.setLabelProcess(i, copies);
                    //printer.printLabel(temp);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(PrintController.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    this.currentLabels++;
                } else {
                    this.cancelLabels();
                }
            }
            this.setLabelProcess(copies, copies);
        }
        this.doneLabels();

    }

    public void print(URI xml, URI pdf, int copies) throws Exception {
        this.printPdf(pdf, copies);
        this.printXml(xml);
    }

    private void setLabelName(String codeValue) {
        parent.setCurrentLabelName(codeValue);
    }

    private void setLabelProcess(int current, int max) {
        parent.setCurrentLabelProcess(current, max);
        parent.setTotalLabelProcess(this.currentLabels, this.totalLabels);
    }

    private void cancelLabels() {
        parent.cancelLabels();
    }

    private void doneLabels() {
        parent.doneLabels();
    }

    public void printPdf(URI pdf, int copies) throws Exception {
        this.pdfStart();
        if (copies > 0) {
            pdfPrint(pdf, this.pdfPrinter, copies);
        }
        this.pdfDone();
    }

    private void pdfPrint(URI uri, String printer, int copies) throws FileNotFoundException, IOException, PrinterException {
        InputStream is = uri.toURL().openStream();
        File temp = File.createTempFile("pdfprint", ".pdf");
        temp.deleteOnExit();

        byte[] b = new byte[1024];

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        int read;
        while ((read = is.read(b)) != -1) {
            os.write(b, 0, read);
        }
        os.close();
        is.close();

        ByteBuffer bb = ByteBuffer.wrap(os.toByteArray());
        PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page
        pdfPrint(pdfFile, printer, copies);
    }

    private void pdfPrint(PDFFile pdfFile, String printer, int copies) throws PrinterException {
        PDFPrintPage pages = new PDFPrintPage(pdfFile);
        PrinterJob pjob = PrinterJob.getPrinterJob();
        if (printer != null && !printer.equals("")) {
            PrintService[] lookupPrintServices = PrinterJob.lookupPrintServices();
            for (PrintService ps : lookupPrintServices) {
                if (ps.getName().contains(printer)) {
                    pjob.setPrintService(ps);
                }
            }
        }
        PageFormat pf = pjob.defaultPage();
        Paper paper = new Paper();
        paper.setSize(594.992125984252, 841.8897637795276);
        paper.setImageableArea(18.0, 18.0, 558.99212598425197, 805.8897637795276);
        pf.setPaper(paper);
        pjob.setJobName("DebGen Pdf print");
        pjob.setCopies(copies);
        Book book = new Book();
        book.append(pages, pf, pdfFile.getNumPages());
        pjob.setPageable(book);
        pjob.print();
    }

    public void setPrinterName(String pdfPrinter) {
        this.pdfPrinter = pdfPrinter;
    }

    private void pdfDone() {
        parent.pdfDone();
    }

    private void startLabels() {
        parent.startlabels();
    }

    private void pdfStart() {
        parent.startPdf();
    }
}
