/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed 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 android.graphics.pdf.cts;

import static android.graphics.pdf.cts.Utils.A4_HEIGHT_PTS;
import static android.graphics.pdf.cts.Utils.A4_PORTRAIT;
import static android.graphics.pdf.cts.Utils.A4_WIDTH_PTS;
import static android.graphics.pdf.cts.Utils.A5_PORTRAIT;
import static android.graphics.pdf.cts.Utils.createRenderer;
import static android.graphics.pdf.cts.Utils.renderAndCompare;
import static android.graphics.pdf.cts.Utils.renderWithTransform;
import static android.graphics.pdf.cts.Utils.verifyException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.pdf.PdfRenderer;
import android.graphics.pdf.PdfRenderer.Page;
import android.graphics.pdf.cts.R;

import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;

/**
 * All test for {@link PdfRenderer} beside the valid transformation parameter tests of {@link
 * PdfRenderer.Page#render}.
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PdfRendererTest {
    private static final int A5_PORTRAIT_PRINTSCALING_DEFAULT =
            R.raw.a5_portrait_rgbb_1_6_printscaling_default;
    private static final int A5_PORTRAIT_PRINTSCALING_NONE =
            R.raw.a5_portrait_rgbb_1_6_printscaling_none;
    private static final int TWO_PAGES = R.raw.two_pages;
    private static final int PROTECTED_PDF = R.raw.protected_pdf;

    private Context mContext;

    @Before
    public void setup() {
        mContext = InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void constructRendererNull() throws Exception {
        verifyException(() -> new PdfRenderer(null), NullPointerException.class);
    }

    @Test
    public void constructRendererFromNonPDF() throws Exception {
        // Open jpg as if it was a PDF
        verifyException(() -> createRenderer(R.raw.testimage, mContext), IOException.class);
    }

    @Test
    public void constructRendererFromProtectedPDF() throws Exception {
        verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);
    }

    @Test
    public void rendererRecoversAfterFailure() throws Exception {
        // Create rendered to prevent lib from being unloaded
        PdfRenderer firstRenderer = createRenderer(A4_PORTRAIT, mContext);

        verifyException(() -> createRenderer(PROTECTED_PDF, mContext), SecurityException.class);

        // We can create new renderers after we failed to create one
        PdfRenderer renderer = createRenderer(TWO_PAGES, mContext);
        renderer.close();

        firstRenderer.close();
    }

    @Test
    public void useRendererAfterClose() throws Exception {
        PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
        renderer.close();

        verifyException(renderer::close, IllegalStateException.class);
        verifyException(renderer::getPageCount, IllegalStateException.class);
        verifyException(renderer::shouldScaleForPrinting, IllegalStateException.class);
        verifyException(() -> renderer.openPage(0), IllegalStateException.class);
    }

    @Test
    public void usePageAfterClose() throws Exception {
        PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
        Page page = renderer.openPage(0);
        page.close();

        // Legacy behavior: The properties are cached, hence they are still available after the page
        //                  is closed
        page.getHeight();
        page.getWidth();
        page.getIndex();
        verifyException(page::close, IllegalStateException.class);

        // Legacy support. An IllegalStateException would be nice by unfortunately the legacy
        // implementation returned NullPointerException
        verifyException(() -> page.render(null, null, null, Page.RENDER_MODE_FOR_DISPLAY),
                NullPointerException.class);

        renderer.close();
    }

    @Test
    public void closeWithOpenPage() throws Exception {
        PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
        Page page = renderer.openPage(0);

        verifyException(renderer::close, IllegalStateException.class);

        page.close();
        renderer.close();
    }

    @Test
    public void openTwoPages() throws Exception {
        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
            // Cannot open two pages at once
            Page page = renderer.openPage(0);
            verifyException(() -> renderer.openPage(1), IllegalStateException.class);

            page.close();
        }
    }

    @Test
    public void testPageCount() throws Exception {
        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
            assertEquals(2, renderer.getPageCount());
        }
    }

    @Test
    public void testOpenPage() throws Exception {
        try (PdfRenderer renderer = createRenderer(TWO_PAGES, mContext)) {
            verifyException(() -> renderer.openPage(-1), IllegalArgumentException.class);
            Page page0 = renderer.openPage(0);
            page0.close();
            Page page1 = renderer.openPage(1);
            page1.close();
            verifyException(() -> renderer.openPage(2), IllegalArgumentException.class);
        }
    }

    @Test
    public void testPageSize() throws Exception {
        try (PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
             Page page = renderer.openPage(0)) {
            assertEquals(A4_HEIGHT_PTS, page.getHeight());
            assertEquals(A4_WIDTH_PTS, page.getWidth());
        }
    }

    @Test
    public void testPrintScaleDefault() throws Exception {
        try (PdfRenderer renderer = createRenderer(A5_PORTRAIT, mContext)) {
            assertTrue(renderer.shouldScaleForPrinting());
        }
    }

    @Test
    public void testPrintScalePDF16Default() throws Exception {
        try (PdfRenderer renderer = createRenderer(A5_PORTRAIT_PRINTSCALING_DEFAULT, mContext)) {
            assertTrue(renderer.shouldScaleForPrinting());
        }
    }

    @Test
    public void testPrintScalePDF16None() throws Exception {
        try (PdfRenderer renderer = createRenderer(A5_PORTRAIT_PRINTSCALING_NONE, mContext)) {
            assertFalse(renderer.shouldScaleForPrinting());
        }
    }

    /**
     * Take 16 color probes in the middle of the 16 segments of the page in the following pattern:
     * <pre>
     * +----+----+----+----+
     * |  0 :  1 :  2 :  3 |
     * +....:....:....:....+
     * |  4 :  5 :  6 :  7 |
     * +....:....:....:....+
     * |  8 :  9 : 10 : 11 |
     * +....:....:....:....+
     * | 12 : 13 : 14 : 15 |
     * +----+----+----+----+
     * </pre>
     *
     * @param bm The bitmap to probe
     *
     * @return The color at the probes
     */
    private @NonNull int[] getColorProbes(@NonNull Bitmap bm) {
        int[] probes = new int[16];

        for (int row = 0; row < 4; row++) {
            for (int column = 0; column < 4; column++) {
                probes[row * 4 + column] = bm.getPixel((int) (bm.getWidth() * (column + 0.5) / 4),
                        (int) (bm.getHeight() * (row + 0.5) / 4));
            }
        }

        return probes;
    }

    /**
     * Implementation for {@link #renderNoTransformationAndComparePointsForScreen} and {@link
     * #renderNoTransformationAndComparePointsForPrint}.
     *
     * @param renderMode The render mode to use
     *
     * @throws Exception If anything was unexpected
     */
    private void renderNoTransformationAndComparePoints(int renderMode) throws Exception {
        Bitmap bm = renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null,
                renderMode, mContext);
        int[] probes = getColorProbes(bm);

        // Compare rendering to expected result. This ensures that all other tests in this class do
        // not accidentally all compare empty bitmaps.
        assertEquals(Color.RED, probes[0]);
        assertEquals(Color.RED, probes[1]);
        assertEquals(Color.GREEN, probes[2]);
        assertEquals(Color.GREEN, probes[3]);
        assertEquals(Color.RED, probes[4]);
        assertEquals(Color.RED, probes[5]);
        assertEquals(Color.GREEN, probes[6]);
        assertEquals(Color.GREEN, probes[7]);
        assertEquals(Color.BLUE, probes[8]);
        assertEquals(Color.BLUE, probes[9]);
        assertEquals(Color.BLACK, probes[10]);
        assertEquals(Color.BLACK, probes[11]);
        assertEquals(Color.BLUE, probes[12]);
        assertEquals(Color.BLUE, probes[13]);
        assertEquals(Color.BLACK, probes[14]);
        assertEquals(Color.BLACK, probes[15]);
    }

    @Test
    public void renderNoTransformationAndComparePointsForScreen() throws Exception {
        renderNoTransformationAndComparePoints(Page.RENDER_MODE_FOR_DISPLAY);
    }

    @Test
    public void renderNoTransformationAndComparePointsForPrint() throws Exception {
        renderNoTransformationAndComparePoints(Page.RENDER_MODE_FOR_PRINT);
    }

    @Test
    public void renderPerspective() throws Exception {
        Matrix transform = new Matrix();

        transform.setValues(new float[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 });

        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, transform,
                        Page.RENDER_MODE_FOR_DISPLAY, mContext), IllegalArgumentException.class);
    }

    @Test
    public void render45degreeRotationTranslationAndScaleAndClip() throws Exception {
        Matrix transform = new Matrix();
        // Rotate on top left corner
        transform.postRotate(45);
        // Move
        transform.postTranslate(A4_WIDTH_PTS / 4, A4_HEIGHT_PTS / 4);
        // Scale to 75%
        transform.postScale(0.75f, 0.75f);
        // Clip
        Rect clip = new Rect(20, 20, A4_WIDTH_PTS - 20, A4_HEIGHT_PTS - 20);

        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, transform,
                Page.RENDER_MODE_FOR_DISPLAY, mContext);
    }

    @Test
    public void renderStreched() throws Exception {
        renderAndCompare(A4_WIDTH_PTS * 4 / 3, A4_HEIGHT_PTS * 3 / 4, A4_PORTRAIT, null, null,
                Page.RENDER_MODE_FOR_DISPLAY, mContext);
    }

    @Test
    public void renderWithClip() throws Exception {
        Rect clip = new Rect(20, 20, A4_WIDTH_PTS - 50, A4_HEIGHT_PTS - 50);
        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
                Page.RENDER_MODE_FOR_DISPLAY, mContext);
    }

    @Test
    public void renderWithAllClipped() throws Exception {
        Rect clip = new Rect(A4_WIDTH_PTS / 2, A4_HEIGHT_PTS / 2, A4_WIDTH_PTS / 2,
                A4_HEIGHT_PTS / 2);
        renderAndCompare(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
                Page.RENDER_MODE_FOR_DISPLAY, mContext);
    }

    @Test
    public void renderWithBadLowerCornerOfClip() throws Exception {
        Rect clip = new Rect(0, 0, A4_WIDTH_PTS + 20, A4_HEIGHT_PTS + 20);
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
                        Page.RENDER_MODE_FOR_DISPLAY, mContext), IllegalArgumentException.class);
    }

    @Test
    public void renderWithBadUpperCornerOfClip() throws Exception {
        Rect clip = new Rect(-20, -20, A4_WIDTH_PTS, A4_HEIGHT_PTS);
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, clip, null,
                        Page.RENDER_MODE_FOR_DISPLAY, mContext), IllegalArgumentException.class);
    }

    @Test
    public void renderTwoModes() throws Exception {
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null,
                        Page.RENDER_MODE_FOR_DISPLAY | Page.RENDER_MODE_FOR_PRINT, mContext),
                IllegalArgumentException.class);
    }

    @Test
    public void renderBadMode() throws Exception {
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null,
                        1 << 30, mContext), IllegalArgumentException.class);
    }

    @Test
    public void renderAllModes() throws Exception {
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null, -1,
                        mContext), IllegalArgumentException.class);
    }

    @Test
    public void renderNoMode() throws Exception {
        verifyException(
                () -> renderWithTransform(A4_WIDTH_PTS, A4_HEIGHT_PTS, A4_PORTRAIT, null, null, 0,
                        mContext), IllegalArgumentException.class);
    }

    @Test
    public void renderOnNullBitmap() throws Exception {
        try (PdfRenderer renderer = createRenderer(A4_PORTRAIT, mContext);
             Page page = renderer.openPage(0)) {
            verifyException(() -> page.render(null, null, null, Page.RENDER_MODE_FOR_DISPLAY),
                    NullPointerException.class);
        }
    }

}
