// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { assert } from 'chrome://resources/js/assert.js';
import { CrLitElement } from 'chrome://resources/lit/v3_0/lit.rollup.js';
import { ChangePageOrigin } from './viewer_bookmark.js';
import { getCss } from './viewer_thumbnail.css.js';
import { getHtml } from './viewer_thumbnail.html.js';
// The maximum widths of thumbnails for each layout (px).
// These constants should be kept in sync with `kMaxWidthPortraitPx` and
// `kMaxWidthLandscapePx` in pdf/thumbnail.cc.
const PORTRAIT_WIDTH = 108;
const LANDSCAPE_WIDTH = 140;
export const PAINTED_ATTRIBUTE = 'painted';
export class ViewerThumbnailElement extends CrLitElement {
    static get is() {
        return 'viewer-thumbnail';
    }
    static get styles() {
        return getCss();
    }
    render() {
        return getHtml.bind(this)();
    }
    static get properties() {
        return {
            clockwiseRotations: { type: Number },
            isActive: {
                type: Boolean,
                reflect: true,
            },
            pageNumber: { type: Number },
        };
    }
    #clockwiseRotations_accessor_storage = 0;
    get clockwiseRotations() { return this.#clockwiseRotations_accessor_storage; }
    set clockwiseRotations(value) { this.#clockwiseRotations_accessor_storage = value; }
    #isActive_accessor_storage = true;
    get isActive() { return this.#isActive_accessor_storage; }
    set isActive(value) { this.#isActive_accessor_storage = value; }
    #pageNumber_accessor_storage = 0;
    get pageNumber() { return this.#pageNumber_accessor_storage; }
    set pageNumber(value) { this.#pageNumber_accessor_storage = value; }
    updated(changedProperties) {
        super.updated(changedProperties);
        if (changedProperties.has('clockwiseRotations')) {
            this.styleCanvas_();
        }
        if (changedProperties.has('isActive') && this.isActive) {
            const scrollIntoViewOptions = {
                block: 'nearest',
            };
            if (document.documentElement.hasAttribute('pdfOopifEnabled')) {
                scrollIntoViewOptions.container = 'nearest';
            }
            this.scrollIntoView(scrollIntoViewOptions);
        }
    }
    set image(imageData) {
        let canvas = this.getCanvas_();
        if (!canvas) {
            canvas = document.createElement('canvas');
            // Prevent copying or saving of the thumbnail image in case the document
            // has restricted access rights.
            canvas.oncontextmenu = e => e.preventDefault();
            this.$.thumbnail.appendChild(canvas);
        }
        canvas.width = imageData.width;
        canvas.height = imageData.height;
        this.styleCanvas_();
        const ctx = canvas.getContext('2d');
        ctx.putImageData(imageData, 0, 0);
    }
    clearImage() {
        if (!this.isPainted()) {
            return;
        }
        // `canvas` can be `null` in tests because `image` is set only in response
        // to the plugin.
        const canvas = this.getCanvas_();
        if (canvas) {
            canvas.remove();
        }
        this.removeAttribute(PAINTED_ATTRIBUTE);
    }
    getClickTarget() {
        return this.$.thumbnail;
    }
    getCanvas_() {
        return this.shadowRoot.querySelector('canvas');
    }
    /**
     * Calculates the CSS size of the thumbnail depending on the rotation, the
     * dimensions of the image data, and the screen resolution. The plugin
     * scales the thumbnail image data by the device to pixel ratio, so that
     * scaling must be taken into account on the UI.
     */
    getThumbnailCssSize_(rotated) {
        const canvas = this.getCanvas_();
        const isPortrait = (canvas.width !== canvas.height) &&
            (canvas.width < canvas.height !== rotated);
        const orientedWidth = rotated ? canvas.height : canvas.width;
        const orientedHeight = rotated ? canvas.width : canvas.height;
        // Try scaling down such that the width of thumbnail is `PORTRAIT_WIDTH` or
        // `LANDSCAPE_WIDTH`, but never scale up to retain the resolution of the
        // thumbnail.
        const cssWidth = Math.min(isPortrait ? PORTRAIT_WIDTH : LANDSCAPE_WIDTH, Math.trunc(orientedWidth / window.devicePixelRatio));
        const scale = cssWidth / orientedWidth;
        const cssHeight = Math.trunc(orientedHeight * scale);
        return { width: cssWidth, height: cssHeight };
    }
    /**
     * Focuses and scrolls the element into view.
     * The default scroll behavior of focus() acts differently than
     * scrollIntoView(), which is called in updated(). This method
     * unifies the behavior.
     */
    focusAndScroll() {
        this.scrollIntoView({ block: 'nearest' });
        this.focus({ preventScroll: true });
    }
    isPainted() {
        return this.hasAttribute(PAINTED_ATTRIBUTE);
    }
    setPainted() {
        this.toggleAttribute(PAINTED_ATTRIBUTE, true);
    }
    onClick_() {
        this.fire('change-page', { page: this.pageNumber - 1, origin: ChangePageOrigin.THUMBNAIL });
    }
    /**
     * Sets the canvas CSS size to maintain the resolution of the thumbnail at any
     * rotation.
     */
    styleCanvas_() {
        assert(this.clockwiseRotations >= 0 && this.clockwiseRotations < 4);
        const canvas = this.getCanvas_();
        if (!canvas) {
            return;
        }
        const div = this.shadowRoot.querySelector('#thumbnail');
        const degreesRotated = this.clockwiseRotations * 90;
        canvas.style.transform = `rotate(${degreesRotated}deg)`;
        // For the purposes of determining the dimensions, a rotation of 180deg is
        // not rotated.
        const rotated = this.clockwiseRotations % 2 !== 0;
        const cssSize = this.getThumbnailCssSize_(rotated);
        div.style.width = `${cssSize.width}px`;
        div.style.height = `${cssSize.height}px`;
        // When rotated, the canvas's height becomes the parent div's width and vice
        // versa.
        canvas.style.width = `${rotated ? cssSize.height : cssSize.width}px`;
        canvas.style.height = `${rotated ? cssSize.width : cssSize.height}px`;
    }
}
customElements.define(ViewerThumbnailElement.is, ViewerThumbnailElement);
