package railo.runtime.text.pdf;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Set;

import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.img.Image;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;

public class PDF2ImagePDFRenderer extends PDF2Image {
	
	public PDF2ImagePDFRenderer(){
		PDFFile.class.getName();// this is needed, that the class throws a error when the PDFRenderer.jar is not in the enviroment
	}

	@Override
	public Image toImage(byte[] input, int pageNumber) throws IOException {
		
		File file = File.createTempFile("pdf2img", "pdf");
		
		try{
			copy(input,file);
			PDFFile pdffile = toPDFFile(file);
			
	        // draw a single page to an image
			PDFPage page = pdffile.getPage(pageNumber);
	        
	        return toImage(page,(int)page.getBBox().getWidth(),(int)page.getBBox().getHeight(),false);
	      
		
		}
		finally{
			deleteEL(file);
		}
	}

	private static Image toImage(PDFPage page, int width, int height,boolean transparent) {
		int w = (int)page.getBBox().getWidth();
		int h = (int)page.getBBox().getHeight();
		java.awt.Rectangle rect = new java.awt.Rectangle(0,0,w,h);
        
        BufferedImage bi = Image.toBufferedImage(page.getImage(
                width, height, //width & height
                rect, // clip rect
                null, // null for the ImageObserver
                !transparent, // fill background with white
                true  // block until drawing is done
                ));
        
        return new Image(bi);
	}

	@Override
	public void writeImages(byte[] input, Set pages, Resource outputDirectory,
			String prefix, String format, int scale, boolean overwrite,
			boolean goodQuality, boolean transparent) throws PageException,
			IOException {
		

		File file = File.createTempFile("pdf2img", "pdf");
		try{
			copy(input,file);
			PDFFile pdf = toPDFFile(file);
		
			Resource res;
			int count = pdf.getNumPages();
			 
			for(int page=1;page<=count;page++) {
				if(pages!=null && !pages.contains(Integer.valueOf(page)))continue;
				res=createDestinationResource(outputDirectory,prefix,page,format,overwrite);
				//res=outputDirectory.getRealResource(prefix+"_page_"+page+"."+format);
				writeImage(pdf,page,res,format,scale,overwrite,goodQuality, transparent);
			}
		}
		finally{
			deleteEL(file);
		}
	}
	
	private static void writeImage(PDFFile pdf, int pageNumber, Resource destination,String format, int scale,
			boolean overwrite, boolean goodQuality, boolean transparent) throws PageException, IOException {
		
		PDFPage page = pdf.getPage(pageNumber);
		
		if(scale<1) throw new ExpressionException("scale ["+scale+"] should be at least 1");
		
		int width = (int)page.getBBox().getWidth();
		int height = (int)page.getBBox().getHeight();
		if(scale!=100){
			double s=(scale)/100d;
			width=	(int)((width)*s);
			height=	(int)((height)*s);
			
			
		}
		Image img=toImage(page, width, height,transparent);
		img.writeOut(destination,format, overwrite, 1f);
	}

	private PDFFile toPDFFile(File file) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(file, "r");
        FileChannel channel = raf.getChannel();
        ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
        return new PDFFile(buf);

	}

	private void deleteEL(File file) {
		try{
		if(!file.delete())file.deleteOnExit();
		}
		catch(Throwable t){}
	}

	private void copy(byte[] input, File file) throws IOException {
		ByteArrayInputStream bais = new ByteArrayInputStream(input);
		FileOutputStream fos = new FileOutputStream(file);
		IOUtil.copy(bais, fos, true,true);
		
	}

}
