package javafxprint;

import java.awt.AWTException;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;

import javax.imageio.ImageIO;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Finishings;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.Sides;

/**
 * 
 * @author Rakesh Menon
 */
public class PrintUtils {
	public static void copy(Node node) throws AWTException, IOException {
		Bounds bounds = node.localToScene(node.getBoundsInLocal());
		int x = (int) bounds.getMinX();
		int y = (int) bounds.getMinY();
		int w = (int) bounds.getWidth();
		int h = (int) bounds.getHeight();

		java.awt.Robot robot = new java.awt.Robot();
		java.awt.image.BufferedImage bi = robot
				.createScreenCapture(new java.awt.Rectangle(x, y, w, h));
		// convert BufferedImage to javafx.scene.image.Image
		java.io.ByteArrayOutputStream stream = new java.io.ByteArrayOutputStream();
		ImageIO.write(bi, "png", stream);
		Image image = new Image(new java.io.ByteArrayInputStream(
				stream.toByteArray()), w, h, true, true);
		// put it to clipboard
		ClipboardContent cc = new ClipboardContent();
		cc.putImage(image);
		Clipboard.getSystemClipboard().setContent(cc);
	}

	public static BufferedImage toBufferedImage(Node node) throws AWTException {
		Bounds bounds = node.localToScene(node.getBoundsInLocal());
		int x = (int) bounds.getMinX();
		int y = (int) bounds.getMinY();
		int w = (int) bounds.getWidth();
		int h = (int) bounds.getHeight();

		java.awt.Robot robot = new java.awt.Robot();
		java.awt.image.BufferedImage bi = robot
				.createScreenCapture(new java.awt.Rectangle(x, y, w, h));
		return bi;
	}

	public static void print(RenderedImage image) throws PrinterException,
			PrintException, IOException {

		System.out.println("PRINTING...");

		DocFlavor docFlavor = DocFlavor.INPUT_STREAM.PNG;

		PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
		attributes.add(new Copies(1));

		PrintService printServices[] = PrintServiceLookup.lookupPrintServices(
				docFlavor, attributes);
		if (printServices.length == 0) {
			System.err.println("PrintService for PNG not available!");
			throw new RuntimeException("PrintService for PNG not available!");
		}

		System.out.println("Got PrintService: " + printServices[0].getName());

		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ImageIO.write(image, "png", out);
		ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

		// Show PrintDialog
		boolean print = PrinterJob.getPrinterJob().printDialog(attributes);

		if (print) {
			DocPrintJob job = printServices[0].createPrintJob();
			Doc doc = new SimpleDoc(in, docFlavor, null);
			job.print(doc, attributes);
			in.close();
		}

		System.out.println("Done PrintService: " + print);
	}
	
	public static void printNode(Node node) throws PrinterException, PrintException, IOException, AWTException {
		print(toBufferedImage(node));
	}
	
	public static void printPostScript(InputStream is) throws PrintException, IOException {
		System.out.println("PRINTING...");

		DocFlavor docFlavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;

		PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
		attributes.add(MediaSizeName.ISO_A4);
		attributes.add(new Copies(1));
		attributes.add(Sides.TWO_SIDED_LONG_EDGE);
		attributes.add(Finishings.STAPLE);

		PrintService printServices[] = PrintServiceLookup.lookupPrintServices(
				docFlavor, attributes);
		for   (PrintService service : printServices)   { 
            System.out.println(service.getName()); 
        }
		if (printServices.length == 0) {
			System.err.println("PrintService for PostScript not available!");
			throw new RuntimeException("PrintService for PostScript not available!");
		}

		//System.out.println("Got PrintService: " + printServices[0].getName());

		// Show PrintDialog
		boolean print = PrinterJob.getPrinterJob().printDialog(attributes);

		if (print) {
			DocPrintJob job = printServices[0].createPrintJob();
			Doc doc = new SimpleDoc(is, docFlavor, null);
			job.print(doc, attributes);
			is.close();
		}

		System.out.println("Done PrintService: " + print);
	}
	
	public static void printPDF(InputStream is) throws PrintException, IOException {
		System.out.println("PRINTING...");

		DocFlavor docFlavor = DocFlavor.INPUT_STREAM.PDF;

		PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
		attributes.add(new Copies(1));

		PrintService printServices[] = PrintServiceLookup.lookupPrintServices(
				docFlavor, attributes);
		for   (PrintService service : printServices)   { 
            System.out.println(service.getName()); 
        }
		if (printServices.length == 0) {
			System.err.println("PrintService for PDF not available!");
			throw new RuntimeException("PrintService for PDF not available!");
		}

		System.out.println("Got PrintService: " + printServices[0].getName());
		

		// Show PrintDialog
		boolean print = PrinterJob.getPrinterJob().printDialog(attributes);
		if (print) {
			DocPrintJob job = printServices[0].createPrintJob();
			Doc doc = new SimpleDoc(is, docFlavor, null);
			job.print(doc, attributes);
			is.close();
		}

//		System.out.println("Done PrintService: " + print);
	}
}