/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox.pdmodel.graphics.optionalcontent;

import java.awt.Color;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import junit.framework.TestCase;

import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentProperties.BaseState;
import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList;

/**
 * Tests optional content group functionality (also called layers).
 *
 * @version $Revision$
 */
public class TestOptionalContentGroups extends TestCase
{

    private File testResultsDir = new File("target/test-output");

    /** {@inheritDoc} */
    @Override
    protected void setUp() throws Exception
    {
        super.setUp();
        testResultsDir.mkdirs();
    }

    /**
     * Tests OCG generation.
     * @throws Exception if an error occurs
     */
    public void testOCGGeneration() throws Exception
    {
        PDDocument doc = new PDDocument();
        try
        {
            //OCGs have been introduced with PDF 1.5
            doc.getDocument().setHeaderString("%PDF-1.5");
            PDDocumentCatalog catalog = doc.getDocumentCatalog();
            catalog.setVersion("1.5");

            //Create new page
            PDPage page = new PDPage();
            doc.addPage(page);
            PDResources resources = page.findResources();
            if( resources == null )
            {
                resources = new PDResources();
                page.setResources( resources );
            }

            //Prepare OCG functionality
            PDOptionalContentProperties ocprops = new PDOptionalContentProperties();
            catalog.setOCProperties(ocprops);
            //ocprops.setBaseState(BaseState.ON); //ON=default

            //Create OCG for background
            PDOptionalContentGroup background = new PDOptionalContentGroup("background");
            ocprops.addGroup(background);
            assertTrue(ocprops.isGroupEnabled("background"));

            //Create OCG for enabled
            PDOptionalContentGroup enabled = new PDOptionalContentGroup("enabled");
            ocprops.addGroup(enabled);
            assertFalse(ocprops.setGroupEnabled("enabled", true));
            assertTrue(ocprops.isGroupEnabled("enabled"));

            //Create OCG for disabled
            PDOptionalContentGroup disabled = new PDOptionalContentGroup("disabled");
            ocprops.addGroup(disabled);
            assertFalse(ocprops.setGroupEnabled("disabled", true));
            assertTrue(ocprops.isGroupEnabled("disabled"));
            assertTrue(ocprops.setGroupEnabled("disabled", false));
            assertFalse(ocprops.isGroupEnabled("disabled"));


            //Add mapping to page
            PDPropertyList props = new PDPropertyList();
            resources.setProperties(props);
            COSName mc0 = COSName.getPDFName("MC0");
            props.putMapping(mc0, background);
            COSName mc1 = COSName.getPDFName("MC1");
            props.putMapping(mc1, enabled);
            COSName mc2 = COSName.getPDFName("MC2");
            props.putMapping(mc2, disabled);

            //Setup page content stream and paint background/title
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, false, false);
            PDFont font = PDType1Font.HELVETICA_BOLD;
            contentStream.beginMarkedContentSequence(COSName.OC, mc0);
            contentStream.beginText();
            contentStream.setFont(font, 14);
            contentStream.moveTextPositionByAmount(80, 700);
            contentStream.drawString("PDF 1.5: Optional Content Groups");
            contentStream.endText();
            font = PDType1Font.HELVETICA;
            contentStream.beginText();
            contentStream.setFont(font, 12);
            contentStream.moveTextPositionByAmount(80, 680);
            contentStream.drawString("You should see a green textline, but no red text line.");
            contentStream.endText();
            contentStream.endMarkedContentSequence();

            //Paint enabled layer
            contentStream.beginMarkedContentSequence(COSName.OC, mc1);
            contentStream.setNonStrokingColor(Color.GREEN);
            contentStream.beginText();
            contentStream.setFont(font, 12);
            contentStream.moveTextPositionByAmount(80, 600);
            contentStream.drawString(
                    "This is from an enabled layer. If you see this, that's good.");
            contentStream.endText();
            contentStream.endMarkedContentSequence();

            //Paint disabled layer
            contentStream.beginMarkedContentSequence(COSName.OC, mc2);
            contentStream.setNonStrokingColor(Color.RED);
            contentStream.beginText();
            contentStream.setFont(font, 12);
            contentStream.moveTextPositionByAmount(80, 500);
            contentStream.drawString(
                    "This is from a disabled layer. If you see this, that's NOT good!");
            contentStream.endText();
            contentStream.endMarkedContentSequence();

            contentStream.close();

            File targetFile = new File(testResultsDir, "ocg-generation.pdf");
            doc.save(targetFile.getAbsolutePath());
        }
        finally
        {
            doc.close();
        }
    }

    /**
     * Tests OCG functions on a loaded PDF.
     * @throws Exception if an error occurs
     */
    public void testOCGConsumption() throws Exception
    {
        File pdfFile = new File(testResultsDir, "ocg-generation.pdf");
        if (!pdfFile.exists())
        {
            testOCGGeneration();
        }

        PDDocument doc = PDDocument.load(pdfFile);
        try
        {
            assertEquals("%PDF-1.5", doc.getDocument().getHeaderString());
            PDDocumentCatalog catalog = doc.getDocumentCatalog();
            assertEquals("1.5", catalog.getVersion());

            PDPage page = (PDPage)catalog.getAllPages().get(0);
            PDPropertyList props = page.findResources().getProperties();
            assertNotNull(props);
            PDOptionalContentGroup ocg = props.getOptionalContentGroup(COSName.getPDFName("MC0"));
            assertNotNull(ocg);
            assertEquals("background", ocg.getName());

            assertNull(props.getOptionalContentGroup(COSName.getPDFName("inexistent")));

            PDOptionalContentProperties ocgs = catalog.getOCProperties();
            assertEquals(BaseState.ON, ocgs.getBaseState());
            Set<String> names = new java.util.HashSet<String>(Arrays.asList(ocgs.getGroupNames()));
            assertEquals(3, names.size());
            assertTrue(names.contains("background"));

            assertTrue(ocgs.isGroupEnabled("background"));
            assertTrue(ocgs.isGroupEnabled("enabled"));
            assertFalse(ocgs.isGroupEnabled("disabled"));

            ocgs.setGroupEnabled("background", false);
            assertFalse(ocgs.isGroupEnabled("background"));

            PDOptionalContentGroup background = ocgs.getGroup("background");
            assertEquals(ocg.getName(), background.getName());
            assertNull(ocgs.getGroup("inexistent"));

            Collection<PDOptionalContentGroup> coll = ocgs.getOptionalContentGroups();
            assertEquals(3, coll.size());
            Set<String> nameSet = new HashSet<String>();
            for (PDOptionalContentGroup ocg2 : coll)
            {
                nameSet.add(ocg2.getName());
            }
            assertTrue(nameSet.contains("background"));
            assertTrue(nameSet.contains("enabled"));
            assertTrue(nameSet.contains("disabled"));
        }
        finally
        {
            doc.close();
        }
    }

}
