package org.apache.pdfbox.examples.pdmodel;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLine;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationMarkup;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class PdfBoxCommentServiceTest {
	Logger logger = Logger.getLogger(PdfBoxCommentServiceTest.class.getName());
	
	public String file;

	@Parameterized.Parameters
	public static Collection getFiles() {
		return Arrays.asList(
				"pdfa2b.pdf",
				"pdfa3b.pdf");
	}

	public PdfBoxCommentServiceTest(String file) {
		super();
		this.file = file;
	}

	@Before
	public void before() {
		
	}
	static final float INCH = 72;
	
	@Test
	public void testPdfBoxExistingPdfWithSimpleTextAnnotation() throws IOException {
		
		InputStream inputStream;
		try {
			inputStream = new FileInputStream("../input-files/" + file);
//			inputStream = new FileInputStream("../input-files/pdfa2b.pdf");
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			throw new RuntimeException(e1);
		}


		PDDocument document = null;
		try {
			document = PDDocument.load(inputStream);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

		PDPage page1 = document.getPage(0);
		try {
			List<PDAnnotation> annotations = page1.getAnnotations();

			// Some basic reusable objects/constants
			// Annotations themselves can only be used once!
			PDColor yellow = new PDColor(new float[] { 1,1,102/255 }, PDDeviceRGB.INSTANCE);


			float pw = page1.getMediaBox().getUpperRightX();
			float ph = page1.getMediaBox().getUpperRightY();

			addPDAnnotationTextMarkup(annotations, yellow, ph);
//			addPDAnnotationMarkupFreeText(annotations, pw, ph);
//			addPDAnnotationLink(annotations, ph);

			// Save the results and ensure that the document is properly closed
			Set<COSDictionary> objectsToWrite = new HashSet();

			// Create the appearance streams.
			// Adobe Reader will always display annotations without appearance streams
			// nicely,
			// but other applications may not.
			for (PDAnnotation ann : annotations) {
				ann.constructAppearances();
			}

			// save the PDF
			// document.save("target/pdfbox_more_annotaions.pdf");
			ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream();

			// new style incremental save: add only the objects that have changed
			objectsToWrite.add(document.getDocumentCatalog().getCOSObject());
			if (document.getDocumentCatalog().getAcroForm() != null) {
				objectsToWrite.add(document.getDocumentCatalog().getAcroForm().getCOSObject());
			}

			objectsToWrite.add(document.getPage(0).getCOSObject());
			for (PDAnnotation ann : annotations) {
				objectsToWrite.add(ann.getCOSObject());
				objectsToWrite.add(ann.getAppearance().getCOSObject());
				objectsToWrite.add((COSDictionary) ann.getAppearance().getNormalAppearance().getCOSObject());
			}
			document.saveIncremental(new FileOutputStream("target/saveIncrementalSimpleAnnotation_" + file), objectsToWrite);

		} finally {
			document.close();
		}
	}

	private void addPDAnnotationLink(List<PDAnnotation> annotations, float ph) {
		//			// Now add the link annotation, so the click on "External URL" works
					PDAnnotationLink txtLink = new PDAnnotationLink();
	//				txtLink.setContents("Some text");
	//				txtLink.setBorderStyle(borderULine);
		
					// Set the rectangle containing the link
					float textWidth = 70000 / 1000 * 18;
					PDRectangle position = new PDRectangle();
					position.setLowerLeftX(INCH);
					position.setLowerLeftY(ph - 1.5f * INCH - 20); // down a couple of points
					position.setUpperRightX(INCH + textWidth);
					position.setUpperRightY(ph - 1.5f * INCH);
					txtLink.setRectangle(position);
		
		//			// add an action
					PDActionURI action = new PDActionURI();
					action.setURI("http://www.pdfbox.org");
					txtLink.setAction(action);
					annotations.add(txtLink);
	}

	private void addPDAnnotationMarkupFreeText(List<PDAnnotation> annotations, float pw, float ph) {
		PDAnnotationMarkup freeTextAnnotation = new PDAnnotationMarkup();
		freeTextAnnotation.getCOSObject().setName(COSName.SUBTYPE, PDAnnotationMarkup.SUB_TYPE_FREETEXT);
		PDColor yellow1 = new PDColor(new float[] { 1, 1, 0 }, PDDeviceRGB.INSTANCE);
		// this sets background only (contradicts PDF specification)
		freeTextAnnotation.setColor(yellow1);
		PDRectangle position = new PDRectangle();
		position.setLowerLeftX(1 * INCH);
		position.setLowerLeftY(ph - 5f * INCH - 3 * INCH);
		position.setUpperRightX(pw - INCH);
		position.setUpperRightY(ph - 5f * INCH);
		freeTextAnnotation.setRectangle(position);
		freeTextAnnotation.setTitlePopup("title popup");
		freeTextAnnotation.setSubject("subject");
		freeTextAnnotation.setContents("contents");
		// Text and border in blue RGB color, "Helv" font, 20 point
		// setDefaultAppearance() missing in 2.0
		freeTextAnnotation.getCOSObject().setString(COSName.DA, "0 0 1 rg /Helv 20 Tf");
		freeTextAnnotation.setIntent("FreeTextCallout");
		COSArray newCallout = new COSArray();
		newCallout
				.setFloatArray(new float[] { 0, ph - 9 * INCH, 3 * INCH, ph - 9 * INCH, 4 * INCH, ph - 8 * INCH });
		// setCallout() missing in 2.0
		freeTextAnnotation.getCOSObject().setItem(COSName.CL, newCallout);
		freeTextAnnotation.getCOSObject();
		// setLineEndingStyle() missing in 2.0
		freeTextAnnotation.getCOSObject().setName(COSName.LE, PDAnnotationLine.LE_OPEN_ARROW);
		annotations.add(freeTextAnnotation);
	}

	private void addPDAnnotationTextMarkup(List<PDAnnotation> annotations, PDColor yellow, float ph) {
		// Now add the markup annotation, a highlight to PDFBox text
		PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
		txtMark.setColor(yellow);
		txtMark.setConstantOpacity((float) 0.2); // 20% transparent
//
//			// Set the rectangle containing the markup
		float textWidth = 7779 / 1000 * 18;
		//logger.info("textWidth=[" + font.getStringWidth("Dodan nov tekst") + "]");
		PDRectangle position = new PDRectangle();
		position.setLowerLeftX(INCH);
		position.setLowerLeftY(ph - INCH - 18);
		position.setUpperRightX(INCH + textWidth);
		position.setUpperRightY(ph - INCH);
		txtMark.setRectangle(position);
//
//			// work out the points forming the four corners of the annotations
//			// set out in anti clockwise form (Completely wraps the text)
//			// OK, the below doesn't match that description.
//			// It's what acrobat 7 does and displays properly!
		float[] quads = new float[8];
		quads[0] = position.getLowerLeftX(); // x1
		quads[1] = position.getUpperRightY() - 2; // y1
		quads[2] = position.getUpperRightX(); // x2
		quads[3] = quads[1]; // y2
		quads[4] = quads[0]; // x3
		quads[5] = position.getLowerLeftY() - 2; // y3
		quads[6] = quads[2]; // x4
		quads[7] = quads[5]; // y5

		txtMark.setQuadPoints(quads);
		txtMark.setContents("A simple comment");
		annotations.add(txtMark);
	}
}
