// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { FormFieldFocusType } from './constants.js';
import { GestureDetector } from './gesture_detector.js';
import { convertFormFocusChangeMessage } from './message_converter.js';
import { SwipeDetector } from './swipe_detector.js';
const channel = new MessageChannel();
const sizer = document.querySelector('#sizer');
const plugin = document.querySelector('embed');
const srcUrl = new URL(plugin.src);
let parentOrigin = srcUrl.origin;
if (parentOrigin === 'chrome-untrusted://print') {
    // Within Print Preview, the source origin differs from the parent origin.
    parentOrigin = 'chrome://print';
}
// Plugin-to-parent message handlers. All messages are passed through, but some
// messages may affect this frame, too.
let caretBrowsingEnabled = false;
let isFormFieldFocused = false;
plugin.addEventListener('message', e => {
    const message = e.data;
    switch (message.type) {
        case 'formFocusChange':
            // TODO(crbug.com/40810904): Ideally, the plugin would just consume
            // interesting keyboard events first.
            const focusedData = convertFormFocusChangeMessage(message);
            isFormFieldFocused = focusedData.focused !== FormFieldFocusType.NONE;
            break;
        case 'rendererPreferencesUpdated':
            const caretBrowsingEnabledData = message;
            caretBrowsingEnabled = caretBrowsingEnabledData.caretBrowsingEnabled;
            break;
        default:
            break;
    }
    channel.port1.postMessage(message);
});
// Parent-to-plugin message handlers. Most messages are passed through, but some
// messages (with handlers that `return` immediately) are meant only for this
// frame, not the plugin.
let isPresentationMode = false;
channel.port1.onmessage = e => {
    switch (e.data.type) {
        case 'focus':
            plugin.focus();
            return;
        case 'setPresentationMode':
            isPresentationMode = e.data.enablePresentationMode;
            gestureDetector.setPresentationMode(isPresentationMode);
            swipeDetector.setPresentationMode(isPresentationMode);
            if (isPresentationMode) {
                document.documentElement.className = 'fullscreen';
            }
            else {
                document.documentElement.className = '';
            }
            break;
        case 'syncScrollToRemote':
            window.scrollTo({
                left: e.data.x,
                top: e.data.y,
                behavior: e.data.isSmooth ? 'smooth' : 'auto',
            });
            channel.port1.postMessage({
                type: 'ackScrollToRemote',
                x: window.scrollX,
                y: window.scrollY,
            });
            return;
        case 'updateSize':
            sizer.style.width = `${e.data.width}px`;
            sizer.style.height = `${e.data.height}px`;
            return;
        case 'viewport':
            // Snoop on "viewport" message to support real RTL scrolling in Print
            // Preview.
            // TODO(crbug.com/40737077): Support real RTL scrolling in the PDF viewer.
            if (parentOrigin === 'chrome://print' && e.data.layoutOptions) {
                switch (e.data.layoutOptions.direction) {
                    case 1:
                        document.dir = 'rtl';
                        break;
                    case 2:
                        document.dir = 'ltr';
                        break;
                    default:
                        document.dir = '';
                        break;
                }
            }
            break;
        default:
            break;
    }
    plugin.postMessage(e.data);
};
// Entangle parent-child message channel.
window.parent.postMessage({ type: 'connect', token: srcUrl.href }, parentOrigin, [channel.port2]);
// Forward "scroll" events back to the parent frame's `Viewport`.
window.addEventListener('scroll', () => {
    channel.port1.postMessage({
        type: 'syncScrollFromRemote',
        x: window.scrollX,
        y: window.scrollY,
    });
});
/**
 * Relays gesture events to the parent frame.
 * @param e The gesture event.
 */
function relayGesture(e) {
    const gestureEvent = e;
    channel.port1.postMessage({
        type: 'gesture',
        gesture: {
            type: gestureEvent.type,
            detail: gestureEvent.detail,
        },
    });
}
const gestureDetector = new GestureDetector(plugin);
for (const type of ['pinchstart', 'pinchupdate', 'pinchend', 'wheel']) {
    gestureDetector.getEventTarget().addEventListener(type, relayGesture);
}
/**
 * Relays swipe events to the parent frame.
 * @param e The swipe event.
 */
function relaySwipe(e) {
    const swipeEvent = e;
    channel.port1.postMessage({
        type: 'swipe',
        direction: swipeEvent.detail,
    });
}
const swipeDetector = new SwipeDetector(plugin);
swipeDetector.getEventTarget().addEventListener('swipe', relaySwipe);
// 
document.addEventListener('pointerdown', e => {
    // Only forward left click.
    if (e.button !== 0) {
        return;
    }
    channel.port1.postMessage({
        type: 'sendClickEvent',
        x: e.clientX,
        y: e.clientY,
    });
});
// 
document.addEventListener('keydown', e => {
    // Only forward potential shortcut keys.
    switch (e.key) {
        case ' ':
            // Preventing Space happens in the "keypress" event handler.
            break;
        case 'PageDown':
        case 'PageUp':
            // Prevent PageDown/PageUp when there are no modifier keys.
            if (!hasKeyModifiers(e)) {
                e.preventDefault();
                break;
            }
            return;
        case 'ArrowDown':
        case 'ArrowLeft':
        case 'ArrowRight':
        case 'ArrowUp':
            if (caretBrowsingEnabled) {
                // Do not prevent default, otherwise the plugin will not handle
                // directional key events.
                break;
            }
            // Don't prevent arrow navigation in form fields, or if modified.
            if (!isFormFieldFocused && !hasKeyModifiers(e)) {
                e.preventDefault();
                break;
            }
            return;
        // 
        case 'Enter':
        // Enter is used to create new text annotations.
        // 
        case 'Escape':
        case 'Tab':
            // Print Preview is interested in Escape and Tab.
            break;
        case '=':
        case '-':
        case '+':
            // Ignore zoom shortcuts in Presentation mode.
            if (isPresentationMode && hasCtrlModifier(e)) {
                e.preventDefault();
            }
            return;
        case 'a':
            // Take over Ctrl+A (but not other combinations like Ctrl-Shift-A).
            // Note that on macOS, "Ctrl" is Command.
            if (hasCtrlModifierOnly(e)) {
                e.preventDefault();
                break;
            }
            return;
        default:
            // Relay (but don't prevent) other shortcuts.
            if (hasCtrlModifier(e)) {
                break;
            }
            return;
    }
    channel.port1.postMessage({
        type: 'sendKeyEvent',
        keyEvent: {
            keyCode: e.keyCode,
            code: e.code,
            key: e.key,
            shiftKey: e.shiftKey,
            ctrlKey: e.ctrlKey,
            altKey: e.altKey,
            metaKey: e.metaKey,
        },
    });
});
// Suppress extra scroll by preventing the default "keypress" handler for Space.
// TODO(crbug.com/40208546): Ideally would prevent "keydown" instead, but this
// doesn't work when a plugin element has focus.
document.addEventListener('keypress', e => {
    switch (e.key) {
        case ' ':
            // Don't prevent Space in form fields.
            if (!isFormFieldFocused) {
                e.preventDefault();
            }
            break;
        default:
            break;
    }
});
// TODO(crbug.com/40792950): Load from pdf_viewer_utils.js instead.
function hasCtrlModifier(e) {
    let hasModifier = e.ctrlKey;
    // 
    return hasModifier;
}
// TODO(crbug.com/40792950): Load from pdf_viewer_utils.js instead.
function hasCtrlModifierOnly(e) {
    let metaModifier = e.metaKey;
    // 
    return hasCtrlModifier(e) && !e.shiftKey && !e.altKey && !metaModifier;
}
// TODO(crbug.com/40792950): Load from chrome://resources/js/util.js instead.
function hasKeyModifiers(e) {
    return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey;
}
