import _ from 'lodash';
import '../../chipper/js/browser/initialize-globals.js';
import '../../assert/js/assert.js';
import '../../globals.js';
import { Utils } from '../../scenery/js/imports.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import ArrayIO from '../../tandem/js/types/ArrayIO.js';
import BooleanIO from '../../tandem/js/types/BooleanIO.js';
import IOType from '../../tandem/js/types/IOType.js';
import NullableIO from '../../tandem/js/types/NullableIO.js';
import NumberIO from '../../tandem/js/types/NumberIO.js';
import ObjectLiteralIO from '../../tandem/js/types/ObjectLiteralIO.js';
import StringIO from '../../tandem/js/types/StringIO.js';
import joist from './joist.js';
import packageJSON from './packageJSON.js';
class SimInfo extends PhetioObject {
    constructor(sim) {
        super({
            tandem: Tandem.GENERAL_MODEL.createTandem('simInfo'),
            phetioType: SimInfo.SimInfoIO,
            phetioReadOnly: true,
            phetioDocumentation: 'A collection of data about the runtime and simulation. Available in the simStarted PhET-iO ' +
                'data stream event, as well as on demand in the PhET-iO state.'
        });
        this.info = {};
        assert && assert(Array.isArray(sim.screens), 'screens should be set and an array');
        // globals
        this.putInfo('url', window.location.href);
        this.putInfo('randomSeed', window.phet.chipper.queryParameters.randomSeed);
        this.putInfo('userAgent', window.navigator.userAgent);
        this.putInfo('language', window.navigator.language);
        this.putInfo('window', `${window.innerWidth}x${window.innerHeight}`); // eslint-disable-line phet/bad-sim-text
        this.putInfo('referrer', document.referrer);
        // from Scenery Utils
        this.putInfo('checkIE11StencilSupport', Utils.checkIE11StencilSupport());
        this.putInfo('isWebGLSupported', phet.chipper.queryParameters.webgl ? Utils.isWebGLSupported : false);
        let canvas;
        let context;
        let backingStorePixelRatio;
        const flags = [];
        // @ts-expect-error - pointerEnabled isn't included in the Typescript definition of window.navigator
        if (window.navigator.pointerEnabled) {
            flags.push('pointerEnabled');
        }
        // @ts-expect-error - msPointerEnabled isn't included in the Typescript definition of window.navigator
        if (window.navigator.msPointerEnabled) {
            flags.push('msPointerEnabled');
        }
        if (!window.navigator.onLine) {
            flags.push('offline');
        }
        try {
            canvas = document.createElement('canvas');
            context = canvas.getContext('2d');
            backingStorePixelRatio = Utils.backingStorePixelRatio(context);
            this.putInfo('pixelRatio', `${window.devicePixelRatio || 1}/${backingStorePixelRatio}`);
            if ((window.devicePixelRatio || 1) / backingStorePixelRatio !== 1) {
                flags.push('pixelRatioScaling');
            }
        }
        catch (e) { } // eslint-disable-line no-empty
        this.putInfo('flags', flags.join(', '));
        canvas = null; // dispose only reference
        // from Sim.js
        this.putInfo('simName', sim.simNameProperty.value);
        this.putInfo('simVersion', sim.version);
        this.putInfo('repoName', packageJSON.name);
        this.putInfo('screens', sim.screens.map((screen) => {
            const screenObject = {
                // likely null for single screen sims, so use the sim name as a default
                name: screen.nameProperty.value || sim.simNameProperty.value
            };
            if (Tandem.PHET_IO_ENABLED) {
                screenObject.phetioID = screen.tandem.phetioID;
            }
            return screenObject;
        }));
        // From PhET-iO code
        if (Tandem.PHET_IO_ENABLED) {
            this.putInfo('screenPropertyValue', sim.selectedScreenProperty.value.tandem.phetioID);
            this.putInfo('wrapperMetadata', phet.preloads.phetio.simStartedMetadata);
            this.putInfo('dataStreamVersion', phet.phetio.dataStream.VERSION);
            this.putInfo('phetioCommandProcessorProtocol', phet.phetio.phetioCommandProcessor.PHET_IO_PROTOCOL);
        }
    }
    putInfo(key, value) {
        if (value === undefined) {
            value = '{{undefined}}';
        }
        assert && assert(!this.info.hasOwnProperty(key), `key already defined: ${key}`);
        // @ts-expect-error I don't know how to ensure the correct value, just the key
        this.info[key] = value;
    }
}
SimInfo.SimInfoIO = new IOType('SimInfoIO', {
    valueType: SimInfo,
    toStateObject: simInfo => {
        return {
            simName: simInfo.info.simName,
            screens: simInfo.info.screens,
            repoName: simInfo.info.repoName,
            screenPropertyValue: simInfo.info.screenPropertyValue,
            dataStreamVersion: simInfo.info.dataStreamVersion,
            phetioCommandProcessorProtocol: simInfo.info.phetioCommandProcessorProtocol,
            simVersion: simInfo.info.simVersion,
            wrapperMetadata: simInfo.info.wrapperMetadata,
            randomSeed: simInfo.info.randomSeed,
            url: simInfo.info.url,
            userAgent: simInfo.info.userAgent,
            window: simInfo.info.window,
            referrer: simInfo.info.referrer,
            language: simInfo.info.language,
            pixelRatio: simInfo.info.pixelRatio,
            isWebGLSupported: simInfo.info.isWebGLSupported,
            checkIE11StencilSupport: simInfo.info.checkIE11StencilSupport,
            flags: simInfo.info.flags || null
        };
    },
    // Do not try to load in a SimInfo
    applyState: _.noop,
    stateSchema: {
        simName: StringIO,
        screens: ArrayIO(ObjectLiteralIO),
        repoName: StringIO,
        screenPropertyValue: StringIO,
        wrapperMetadata: NullableIO(ObjectLiteralIO),
        dataStreamVersion: StringIO,
        phetioCommandProcessorProtocol: StringIO,
        // Parts that are omitted in API generation
        simVersion: NullableIO(StringIO),
        randomSeed: NullableIO(NumberIO),
        url: NullableIO(StringIO),
        userAgent: NullableIO(StringIO),
        window: NullableIO(StringIO),
        referrer: NullableIO(StringIO),
        language: NullableIO(StringIO),
        pixelRatio: NullableIO(StringIO),
        isWebGLSupported: NullableIO(BooleanIO),
        checkIE11StencilSupport: NullableIO(BooleanIO),
        flags: NullableIO(StringIO)
    },
    apiStateKeys: [
        'screens',
        'repoName',
        'dataStreamVersion',
        'phetioCommandProcessorProtocol'
    ]
});
joist.register('SimInfo', SimInfo);
export default SimInfo;
//# sourceMappingURL=SimInfo.js.map