// Copyright 2018 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 { sendWithPromise } from 'chrome://resources/js/cr.js';
import { getRequiredElement } from 'chrome://resources/js/util.js';
// Timer for automatic update in monitoring mode.
let fetchDiffScheduler = null;
// Contains names for expanded histograms.
const expandedEntries = new Set();
// Whether the page is in Monitoring mode.
let inMonitoringMode = false;
/**
 * Returns a boolean that will be true when histogram from subprocesses should
 * be included.
 */
function includeSubprocessMetrics() {
    const checkbox = getRequiredElement('subprocess_checkbox');
    return checkbox.checked;
}
/** Sends a request to the given handler. */
function sendRequest(handlerName) {
    return sendWithPromise(handlerName, getQuery(), includeSubprocessMetrics());
}
/**
 * Initiates the request for histograms.
 */
function requestHistograms() {
    sendRequest('requestHistograms').then(addHistograms);
}
/** Clears all loaded histograms on the webpage. */
function clearHistograms() {
    getRequiredElement('histograms').innerHTML = window.trustedTypes.emptyHTML;
}
/** Makes the subprocess checkbox disabled, and sets a tooltip. */
function disableSubprocessCheckbox() {
    const subprocessCheckbox = getRequiredElement('subprocess_checkbox');
    subprocessCheckbox.disabled = true;
    subprocessCheckbox.title = 'Checkbox is disabled in Monitoring Mode. ' +
        'To enable, switch to Histogram Mode first.';
}
/** Makes the subprocess checkbox enabled. */
function enableSubprocessCheckbox() {
    const subprocessCheckbox = getRequiredElement('subprocess_checkbox');
    subprocessCheckbox.disabled = false;
    subprocessCheckbox.removeAttribute('title');
}
/**
 * Starts monitoring histograms.
 * This will get a histogram snapshot as the base to be diffed against.
 */
function startMonitoring() {
    const stopButton = getRequiredElement('stop');
    stopButton.disabled = false;
    stopButton.textContent = 'Stop';
    disableSubprocessCheckbox();
    clearHistograms();
    sendRequest('startMonitoring').then(fetchDiff);
}
/**
 * Schedules the fetching of histogram diff (after 1000ms) and rendering it.
 * This will also recursively call the next fetchDiff() to periodically update
 * the page.
 */
function fetchDiff() {
    fetchDiffScheduler = setTimeout(function () {
        sendRequest('fetchDiff').then(addHistograms).then(fetchDiff);
    }, 1000);
}
/**
 * Gets the query string from the URL.
 *
 * For example, if the URL is
 *   - "chrome://histograms/#abc" or
 *   - "chrome://histograms/abc"
 * then the query is "abc". The "#" format is canonical. The bare format is
 * historical. "Blink.ImageDecodeTimes.Png" is a valid histogram name but the
 * ".Png" pathname suffix can cause the bare histogram page to be served as
 * image/png instead of text/html.
 *
 * See WebUIDataSourceImpl::GetMimeType in
 * content/browser/webui/web_ui_data_source_impl.cc for Content-Type sniffing.
 */
function getQuery() {
    if (document.location.hash) {
        return document.location.hash.substring(1);
    }
    else if (document.location.pathname) {
        return document.location.pathname.substring(1);
    }
    return '';
}
/**
 * Callback function when users switch to Monitoring mode.
 */
function enableMonitoring() {
    inMonitoringMode = true;
    getRequiredElement('accumulating_section').style.display = 'none';
    getRequiredElement('monitoring_section').style.display = 'block';
    expandedEntries.clear();
    startMonitoring();
}
/**
 * Callback function when users switch away from Monitoring mode.
 */
function disableMonitoring() {
    inMonitoringMode = false;
    if (fetchDiffScheduler) {
        clearTimeout(fetchDiffScheduler);
        fetchDiffScheduler = null;
    }
    getRequiredElement('accumulating_section').style.display = 'block';
    getRequiredElement('monitoring_section').style.display = 'none';
    clearHistograms();
    enableSubprocessCheckbox();
    expandedEntries.clear();
    requestHistograms();
}
/**
 * Callback function when users click the stop button in monitoring mode.
 */
function stopMonitoring() {
    if (fetchDiffScheduler) {
        clearTimeout(fetchDiffScheduler);
        fetchDiffScheduler = null;
    }
    const stopButton = getRequiredElement('stop');
    stopButton.disabled = true;
    stopButton.textContent = 'Stopped';
}
/**
 * Returns if monitoring mode is stopped.
 */
export function monitoringStopped() {
    return inMonitoringMode && !fetchDiffScheduler;
}
function onHistogramHeaderClick(event) {
    const headerElement = event.currentTarget;
    const name = headerElement.getAttribute('histogram-name');
    assert(name);
    const shouldExpand = !expandedEntries.has(name);
    if (shouldExpand) {
        expandedEntries.add(name);
    }
    else {
        expandedEntries.delete(name);
    }
    setExpanded(headerElement.parentElement, shouldExpand);
}
/**
 * Expands or collapses a histogram node.
 * @param histogramNode the histogram element to expand or collapse
 * @param expanded whether to expand or collapse the node
 */
function setExpanded(histogramNode, expanded) {
    const body = histogramNode.querySelector('.histogram-body');
    const expand = histogramNode.querySelector('.expand');
    const collapse = histogramNode.querySelector('.collapse');
    assert(body && expand && collapse);
    body.style.display = expanded ? 'block' : 'none';
    expand.style.display = expanded ? 'none' : 'inline';
    collapse.style.display = expanded ? 'inline' : 'none';
}
/**
 * Callback from backend with the list of histograms. Builds the UI.
 * @param histograms A list of name, header and body strings representing
 *     histograms.
 */
function addHistograms(histograms) {
    clearHistograms();
    // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
    for (const histogram of histograms) {
        const { name, header, body } = histogram;
        const template = document.body.querySelector('#histogram-template');
        assert(template);
        const clone = template.content.cloneNode(true);
        const headerNode = clone.querySelector('.histogram-header');
        assert(headerNode);
        headerNode.setAttribute('histogram-name', name);
        headerNode.onclick = onHistogramHeaderClick;
        clone.querySelector('.histogram-header-text').textContent = header;
        const link = clone.querySelector('.histogram-header-link');
        assert(link);
        link.href = '/#' + name;
        // Don't run expand/collapse handler on link click.
        link.onclick = (e) => e.stopPropagation();
        clone.querySelector('p').textContent = body;
        // If we are not in monitoring mode, default to expand.
        if (!inMonitoringMode) {
            expandedEntries.add(name);
        }
        // In monitoring mode, we want to preserve the expanded/collapsed status
        // between reloads.
        setExpanded(clone, expandedEntries.has(name));
        getRequiredElement('histograms').appendChild(clone);
    }
    getRequiredElement('histograms')
        .dispatchEvent(new CustomEvent('histograms-updated-for-test'));
}
/**
 * Returns the histograms as a formatted string.
 */
export function generateHistogramsAsText() {
    // Expanded/collapsed status is reflected in the text.
    return getRequiredElement('histograms').innerText;
}
/**
 * Callback function when users click the Download button.
 */
function downloadHistograms() {
    const text = generateHistogramsAsText();
    if (text) {
        const file = new Blob([text], { type: 'text/plain' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(file);
        a.download = 'histograms.txt';
        a.click();
    }
}
function handleHashChange() {
    // In monitoring mode the updated histograms will be fetched by fetchDiff()
    // within 1s of changing URL and the proper filter will be applied.
    if (!inMonitoringMode) {
        requestHistograms();
    }
}
/**
 * Load the initial list of histograms.
 */
document.addEventListener('DOMContentLoaded', function () {
    getRequiredElement('refresh').onclick = requestHistograms;
    getRequiredElement('download').onclick = downloadHistograms;
    getRequiredElement('enable_monitoring').onclick = enableMonitoring;
    getRequiredElement('disable_monitoring').onclick = disableMonitoring;
    getRequiredElement('stop').onclick = stopMonitoring;
    getRequiredElement('subprocess_checkbox').onclick = requestHistograms;
    requestHistograms();
});
/**
 * Reload histograms when the "#abc" in "chrome://histograms/#abc" changes.
 */
window.onhashchange = handleHashChange;
