package de.geis.printserver;

import java.awt.print.PrinterJob;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.JobName;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPageable;


public class PrintMap extends Thread {

	private File pdffile = null;
	@SuppressWarnings("unused")
	private static boolean jobRunning = true;

	PDDocument m_pdDocument = null;
	
	private final Map<File, Property> m_propertyMap;
	public PrintMap(Map<File, Property> propertyMap) {
		super();
		m_propertyMap = propertyMap;
	}
	
	public boolean printPdfNotEmulate(Property property, int copies) {
		boolean status = true;
		
		for (int i = 0; i < copies; i++) {
			System.out.println("IM NICHT EMULIERT");	
			status = printPdfNotEmulate(property);
		}
		
		return status;
	}
	

	private boolean printPdfToZebra(Property property) {
		boolean status = true;
		PrinterJob printerJob = null;
		
		try {
			printerJob = PrinterJob.getPrinterJob();
	    	PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 

			printerJob.setPageable(new PDFPageable(m_pdDocument));
			printerJob.setPrintService(findPrintService(property.getPrintername()));
			printerJob.setJobName(fillString(property.getSpoolname(), 10, " ", false) + property.getJobnummer());
	    	
			if (property.getCopies() > 1) {
				printerJob.setCopies(property.getCopies());
				System.out.println("Kopien: " + property.getCopies());
			}
			
			
			printerJob.print(aset);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			if (m_pdDocument != null) {
				try {
					m_pdDocument.close();	
				} catch (Exception e2) { }
			}
		}
		
		
		return status;
	}
	
	public boolean printZPLToZebra (Property property) {
		InputStream fileInputStream = null;
		try {			
	    	PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 
	    	
			fileInputStream = Files.newInputStream(Paths.get(property.getPdfname()));

	    	PrintService service = findPrintService(property.getPrintername());
	    	DocFlavor psInFormat = DocFlavor.INPUT_STREAM.AUTOSENSE;
	    	Doc pdfDoc = new SimpleDoc(fileInputStream, psInFormat, null);
	    	aset.add(new JobName(fillString(property.getSpoolname(), 10, " ", false) + property.getJobnummer(), null));
	            	
	    	DocPrintJob printJob = service.createPrintJob();
	    	 
	    	printJob.addPrintJobListener(new JobCompleteMonitor());

	    	printJob.print(pdfDoc, aset);
	    	
		} catch (Exception e) {
			return false;
		} finally {
    		try {
    			fileInputStream.close();
    		} catch (Exception io) {
    			return false;
    		}
    	}
		return true;
	}	
	
	public boolean printPdfNotEmulate(Property property) {

		InputStream fileInputStream = null;
    	try {
			fileInputStream = Files.newInputStream(Paths.get(property.getPdfname()));
			
	    	PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 
	    	
	    	PrintService service = findPrintService(property.getPrintername());
	    	DocFlavor psInFormat = DocFlavor.INPUT_STREAM.AUTOSENSE;
	    	
	    	Doc pdfDoc = new SimpleDoc(fileInputStream, psInFormat, null);
	    	
	    	DocPrintJob printJob = service.createPrintJob();
		
	    	printJob.addPrintJobListener(new JobCompleteMonitor());

	    	aset.add(new JobName(fillString(property.getSpoolname(), 10, " ", false) + property.getJobnummer(), null));
	    	
	    	printJob.print(pdfDoc, aset);
	    	
		} catch (Exception e) {
			return false;
		} finally {
    		try {
    			fileInputStream.close();
    		} catch (IOException io) {
    			return false;
    		}
    	}
		return true;
    }
	
	
	private static class JobCompleteMonitor extends PrintJobAdapter {
		
		@Override
		public void printJobCompleted(PrintJobEvent jobEvent) {
			System.out.println("Job completed");
		           jobRunning = false;
		}
		
	}


	public void print() {
		
		boolean delete = true;
		FileOutputStream fileOutputStream = null;
		ArrayList<File> removeFile = new ArrayList<File>();
		
		for (File elem : m_propertyMap.keySet()) {
			System.out.println("ELEM"+ elem);
			Property property = m_propertyMap.get(elem);
			boolean status = true;
			if (!property.getPdfname().endsWith(".zpl")) {
				status = loadPdf(m_propertyMap.get(elem).getPdfname());
			}
			else {
				status = loadZPL(m_propertyMap.get(elem).getPdfname());
			}
			
			try {
				
				if (status == false) {
					createErrorProperty(ErrorCodes.DOKUMENT.getValue(), elem);
					delete = false;
					continue;
				}
				
				if (property.getPdfname().endsWith(".zpl")) {
					status = printZPLToZebra(property);
				}
				
				else if (property.getZebraPrinter()) {
					status = printPdfToZebra(property);
				}
				
				
			
				else if (property.getPdfemulate()) {
					status = printPdfEmulate(property);
				} 
				else {
					if (property.getCopies() > 1) {
						status = printPdfNotEmulate(property, property.getCopies());
					} else {
						status = printPdfNotEmulate(property);
					}
				}

				} catch (Exception e) {
					delete = false;
					
					createErrorProperty(ErrorCodes.PRINTER.getValue(), elem);

				} finally {
					
					if (status) {
						System.out.println("Success: " + elem);
						removeFile.add(elem);
					}
					
					if (fileOutputStream != null) {
						try {
							fileOutputStream.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					if (m_pdDocument != null) {
						try {	    				
							m_pdDocument.close();
							pdffile.delete();
							pdffile = null;
						} catch (IOException io) {
						}
					}
					else {
						try {	    				
							pdffile.delete();
							pdffile = null;
						} catch (Exception io) {
						}
					}
				}
		}
		if(delete == true) {
			for (File elem : removeFile) {
				m_propertyMap.remove(elem);
			}
			
		}
    }
	
	private boolean printPdfEmulate(Property property) {
		boolean status = true;
		PrinterJob printerJob = null;
		
		try {
			System.out.println("EMULIERT");
			printerJob = PrinterJob.getPrinterJob();
	    	PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 

			printerJob.setPageable(new PDFPageable(m_pdDocument));
			printerJob.setPrintService(findPrintService(property.getPrintername()));
			printerJob.setJobName(fillString(property.getSpoolname(), 10, " ", false) + property.getJobnummer());
			
	    	//aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
	    	
			if (property.getCopies() > 1) {
				printerJob.setCopies(property.getCopies());
				System.out.println("Kopien: " + property.getCopies());
			}
			
			
			printerJob.print(aset);
		} catch (Exception e) {
			return false;
		} finally {
			if (m_pdDocument != null) {
				try {
					m_pdDocument.close();	
				} catch (Exception e2) { }
			}
		}
		
		
		return status;
	}

	public boolean loadPdf(String pdfFileName) {
		boolean status = false;
		try {
			pdffile = new File(pdfFileName);
			
			if (pdffile.exists() == true) {
				m_pdDocument = PDDocument.load(pdffile);
				status = true;
			} 
		} catch (IOException e) {
			status = false;
		}
		return status;
	}
	
	public boolean loadZPL(String zplName) {
		boolean status = false;
		
		try {
			pdffile = new File(zplName);
			
			if (pdffile.exists()) {
				status = true;
			}
		} catch (Exception e) {
			status = false;
		}
		return status;
	}
	
	static public String fillString(Object data, int totaleLenght, String fillWith, boolean isRight) {
		StringBuffer stringFueller = new StringBuffer();
		if (data == null) {
			data = "";
		}
		for (int i = 0; i < totaleLenght - data.toString().length(); ++i) {
			stringFueller.append(fillWith);
		}
		return isRight ? stringFueller.toString() + data : data + stringFueller.toString();
	}
	
	private PrintService findPrintService(String printerName) {
    	PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
    	for (PrintService printService : printServices) {
    		if (printService.getName().trim().equals(printerName)) {
    			return printService;
    		}
    	}
    	return null;
    }
	
//	public void setDaten(Map<File, Property> propertyMap) {
//		m_propertyMap = propertyMap;
//	}
	
	private void createErrorProperty(String status, File file) {
		FileOutputStream fileOutputStream = null;
		Properties props = new Properties();
		
		System.out.println(status + ", FILE : " + file);
		
		try {
			props.setProperty("STATUS", status);
			props.setProperty("PRINTERNAME", m_propertyMap.get(file).getPrintername());
			props.setProperty("JOBNUMMER", m_propertyMap.get(file).getJobnummer());
			props.setProperty("PDFNAME", m_propertyMap.get(file).getPdfname());
			props.setProperty("SPOOLNAME", m_propertyMap.get(file).getSpoolname());
			props.setProperty("PDFEMULATE", m_propertyMap.get(file).getPdfemulate().toString());
			props.setProperty("COPIES", m_propertyMap.get(file).getCopies().toString());
			props.setProperty("ZEBRAPRINT", m_propertyMap.get(file).getZebraPrinter().toString());
			
			fileOutputStream = new FileOutputStream(Parameters.getErrorFolder() + "\\" + file.getName());
			props.store(fileOutputStream, null);
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fileOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	 
	 
	@Override
	public void run() {		
		try {
			print();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}
