// 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 { skColorToRgba } from 'chrome://resources/js/color_utils.js';
import { EventTracker } from 'chrome://resources/js/event_tracker.js';
import { PromiseResolver } from 'chrome://resources/js/promise_resolver.js';
import { strictQuery } from './utils.js';
import { WindowProxy } from './window_proxy.js';
/**
 * @fileoverview The background manager brokers access to background related
 * DOM elements. The reason for this abstraction is that the these elements are
 * not owned by any custom elements (this is done so that the aforementioned DOM
 * elements load faster at startup).
 *
 * The background manager expects an iframe with ID 'backgroundImage' to be
 * present in the DOM. It will use that element to set the background image URL.
 */
/**
 * Installs a listener for background image load times and manages a
 * |PromiseResolver| that resolves to the captured load time.
 */
class LoadTimeResolver {
    resolver_ = new PromiseResolver();
    eventTracker_ = new EventTracker();
    constructor(url) {
        this.eventTracker_.add(window, 'message', ({ data }) => {
            if (data.frameType === 'background-image' &&
                data.messageType === 'loaded' && url === data.url) {
                this.resolve_(data.time);
            }
        });
    }
    get promise() {
        return this.resolver_.promise;
    }
    reject() {
        this.resolver_.reject();
        this.eventTracker_.removeAll();
    }
    resolve_(loadTime) {
        this.resolver_.resolve(loadTime);
        this.eventTracker_.removeAll();
    }
}
let instance = null;
export class BackgroundManager {
    static getInstance() {
        return instance || (instance = new BackgroundManager());
    }
    static setInstance(newInstance) {
        instance = newInstance;
    }
    backgroundImage_;
    loadTimeResolver_ = null;
    url_;
    constructor() {
        this.backgroundImage_ =
            strictQuery(document.body, '#backgroundImage', HTMLIFrameElement);
        this.url_ = this.backgroundImage_.src;
    }
    /**
     * Sets whether the background image should be shown.
     * @param show True, if the background image should be shown.
     */
    setShowBackgroundImage(show) {
        document.body.toggleAttribute('show-background-image', show);
    }
    /** Sets the background color. */
    setBackgroundColor(color) {
        document.body.style.backgroundColor = skColorToRgba(color);
    }
    /** Sets the background image. */
    setBackgroundImage(image) {
        const url = new URL('chrome-untrusted://new-tab-page/custom_background_image');
        url.searchParams.append('url', image.url);
        if (image.url2x) {
            url.searchParams.append('url2x', image.url2x);
        }
        if (image.size) {
            url.searchParams.append('size', image.size);
        }
        if (image.repeatX) {
            url.searchParams.append('repeatX', image.repeatX);
        }
        if (image.repeatY) {
            url.searchParams.append('repeatY', image.repeatY);
        }
        if (image.positionX) {
            url.searchParams.append('positionX', image.positionX);
        }
        if (image.positionY) {
            url.searchParams.append('positionY', image.positionY);
        }
        if (url.href === this.url_) {
            return;
        }
        if (this.loadTimeResolver_) {
            this.loadTimeResolver_.reject();
            this.loadTimeResolver_ = null;
        }
        // We use |contentWindow.location.replace| because reloading the iframe by
        // setting its |src| adds a history entry.
        this.backgroundImage_.contentWindow.location.replace(url.href);
        // We track the URL separately because |contentWindow.location.replace| does
        // not update the iframe's src attribute.
        this.url_ = url.href;
    }
    /**
     * Returns promise that resolves with the background image load time.
     *
     * The background image iframe proactively sends the load time as soon as it
     * has loaded. However, this could be before we have installed the message
     * listener in LoadTimeResolver. Therefore, we request the background image
     * iframe to resend the load time in case it has already loaded. With that
     * setup we ensure that the load time is (re)sent _after_ both the NTP top
     * frame and the background image iframe have installed the required message
     * listeners.
     */
    getBackgroundImageLoadTime() {
        if (!this.loadTimeResolver_) {
            this.loadTimeResolver_ = new LoadTimeResolver(this.backgroundImage_.src);
            WindowProxy.getInstance().postMessage(this.backgroundImage_, 'sendLoadTime', 'chrome-untrusted://new-tab-page');
        }
        return this.loadTimeResolver_.promise;
    }
}
