import '../../../assert/js/assert.js';
import '../PhetioIDUtils.js';
import '../../../globals.js';
import { Validator } from '../../../axon/js/Validation.js';
import IntentionalAny from '../../../phet-core/js/types/IntentionalAny.js';
import PhetioDynamicElementContainer from '../PhetioDynamicElementContainer.js';
import type PhetioObject from '../PhetioObject.js';
import { IOTypeName, PhetioElementMetadata, PhetioType } from '../TandemConstants.js';
import StateSchema, { APIStateKeys, CompositeSchema } from './StateSchema.js';
type AddChildElement = (group: PhetioDynamicElementContainer<PhetioObject>, componentName: string, stateObject: unknown) => PhetioObject;
export type IOTypeMethod = {
    returnType: IOType;
    parameterTypes: IOType[];
    implementation: (...args: IntentionalAny[]) => unknown;
    documentation: string;
    invocableForReadOnlyElements?: boolean;
};
type DeserializationType = 'fromStateObject' | 'applyState';
type StateSchemaOption<T, StateType extends SelfStateType, SelfStateType> = ((ioType: IOType<T, StateType, SelfStateType>) => CompositeSchema<SelfStateType>) | StateSchema<T, StateType> | CompositeSchema<SelfStateType> | null;
type SelfOptions<T, StateType extends SelfStateType, SelfStateType> = {
    supertype?: IOType | null;
    events?: string[];
    dataDefaults?: Record<string, unknown>;
    metadataDefaults?: Partial<PhetioElementMetadata>;
    documentation?: string;
    methods?: Record<string, IOTypeMethod>;
    methodOrder?: string[];
    parameterTypes?: IOType[];
    isFunctionType?: boolean;
    stateSchema?: StateSchemaOption<T, StateType, SelfStateType>;
    /**
     * A list of keys found in this IOType's composite state that should be API tracked.
     * Initial states are tracked in api file for each stateful instance, this means that those value changes can
     * trigger api changes. This doesn't occur by default, so instead you must opt into to value-based api tracking like
     * this.
     * This option is mostly recognizing that it is less than ideal the metadata the describes what kind of values
     * a PhEt-iO Element could be are in state, even though they probably shouldn't be. Like PropertyIO.validValues. We
     * are likely never going to change that, due to complexity and backwards compatibility needs, so this option allows
     * API tracking for state like that, without incurring the cost of tracking useless value changes (PropertyIO.value,
     * for example).
     *
     * By default, state used by another PhET-iO Element that is opting into api tracking will be added to the API. For
     * example, because PropertyIO.validValues opts into api tracking, a PropertyIO<RangeIO> will show validValues with full
     * RangeIO state objects in it. This is because RangeIO doesn't provide any apiStateKeys. Thus, we say that nested
     * state objects are "opt out" for this behavior, since you could remove the min/max keys from the above example if
     * you provided apiStateKeys:[], instead of the default of "null".
     *
     * NOTE! These are still just values! They will still be set for state, and it doesn't exclude you from any state-like
     * behavior. This option doesn't change anything for state-setting, just for the logic of API comparison/compatibility
     * checking.
     *
     * Solution developed in https://github.com/phetsims/phet-io/issues/1951
     */
    apiStateKeys?: APIStateKeys | null;
    toStateObject?: ((t: T) => StateType) | null;
    fromStateObject?: ((s: StateType) => T) | null;
    stateObjectToCreateElementArguments?: ((s: StateType) => unknown[]) | null;
    applyState?: ((t: T, state: StateType) => void) | null;
    defaultDeserializationMethod?: DeserializationType;
    addChildElement?: AddChildElement;
};
type IOTypeOptions<T, StateType extends SelfStateType, SelfStateType> = SelfOptions<T, StateType, SelfStateType> & Validator<T>;
export default class IOType<T = any, StateType extends SelfStateType = any, SelfStateType = StateType> {
    readonly typeName: IOTypeName;
    readonly supertype?: IOType;
    readonly documentation?: string;
    readonly methods?: Record<string, IOTypeMethod>;
    readonly events: string[];
    readonly metadataDefaults?: Partial<PhetioElementMetadata>;
    readonly dataDefaults?: Record<string, unknown>;
    readonly methodOrder?: string[];
    readonly parameterTypes?: IOType[];
    private readonly toStateObjectOption;
    readonly fromStateObjectOption: ((state: StateType) => T) | null;
    private readonly applyStateOption;
    readonly stateObjectToCreateElementArgumentsOption: ((s: StateType) => unknown[]) | null;
    readonly addChildElement: AddChildElement;
    readonly validator: Validator<T>;
    readonly defaultDeserializationMethod: DeserializationType;
    readonly isFunctionType: boolean;
    readonly stateSchema: StateSchema<T, SelfStateType> | null;
    static ObjectIO: IOType;
    private readonly toStateObjectSupplied;
    private readonly stateSchemaSupplied;
    private readonly applyStateSupplied;
    /**
     * @param typeName - The name that this IOType will have in the public PhET-iO API. In general, this should
     *    only be word characters, ending in "IO". Parametric types are a special subset of IOTypes that include their
     *    parameters in their typeName. If an IOType's parameters are other IOType(s), then they should be included within
     *    angle brackets, like "PropertyIO<BooleanIO>". Some other types use a more custom format for displaying their
     *    parameter types, in this case the parameter section of the type name (immediately following "IO") should begin
     *    with an open paren, "(". Thus the schema for a typeName could be defined (using regex) as `[A-Z]\w*IO([(<].*){0,1}`.
     *    Parameterized types should also include a `parameterTypes` field on the IOType.
     * @param providedOptions
     */
    constructor(typeName: IOTypeName, providedOptions: IOTypeOptions<T, StateType, SelfStateType>);
    toStateObject(coreObject: T): StateType;
    fromStateObject(stateObject: StateType): T;
    applyState(coreObject: T, stateObject: StateType): void;
    stateObjectToCreateElementArguments(stateObject: StateType): unknown[];
    private defaultToStateObject;
    private defaultApplyState;
    /**
     * Gets an array of IOTypes of the self type and all the supertype ancestors.
     */
    private getTypeHierarchy;
    /**
     * Returns true if this IOType is a subtype of the passed-in type (or if they are the same).
     */
    extends(type: IOType<unknown, unknown>): boolean;
    /**
     * Return all the metadata defaults (for the entire IOType hierarchy)
     */
    getAllMetadataDefaults(): Partial<PhetioElementMetadata>;
    /**
     * Return all the data defaults (for the entire IOType hierarchy)
     */
    getAllDataDefaults(): Record<string, unknown>;
    /**
     * This cannot be in stateSchema, because some IOTypes do not have stateSchema instances, but their supertype does.
     */
    private isCompositeStateSchema;
    /**
     * Return all the apiStateKey option values (for the entire IOType hierarchy)
     * For example:
     *  [ null, null, ['validValues'], null ] if there were three supertypes, and your parent was the only IOType with apiStateKeys
     */
    private getAllAPIStateKeyValues;
    /**
     * See if any IOType up the hierarchy actually supplied apiStateKeys, even in `[]`, meaning "don't opt-in to nested
     * API state.
     */
    private apiStateKeysProvided;
    /**
     * Return all the apiStateKeys (for the entire IOType hierarchy) in one array.
     */
    getAllAPIStateKeys(): APIStateKeys;
    /**
     * Get the state object for a PhET-iO Element, but only the entries that should be tracked by the PhET-iO API. See
     * StateSchema.apiStateKeys for details. This implementation sets a global to make sure that nested state also only
     * selects the apiStateKeys for api tracking (PropertyIO<RangeIO> could have validValues of PointIO that shouldn't
     * include non-tracked values of PointIO, if there are any).
     */
    toStateObjectForAPI(coreObject: T): StateType;
    /**
     * @param stateObject - the stateObject to validate against
     * @param toAssert=false - whether to assert when invalid
     * @param schemaKeysPresentInStateObject=[]
     * @returns if the stateObject is valid or not.
     */
    isStateObjectValid(stateObject: StateType, toAssert?: boolean, schemaKeysPresentInStateObject?: string[]): boolean;
    /**
     * Assert if the provided stateObject is not valid to this IOType's stateSchema
     */
    validateStateObject(stateObject: StateType): void;
    toString(): IOTypeName;
    /**
     * Return an object that indicates the API type, including documentation, methods & signatures, supertypes, etc.
     * The object is intended for serialization via JSON.stringify().
     *
     * This function could be static, but that doesn't work well with the singleton pattern, so keep in on the prototype.
     */
    getAPI(): PhetioType;
}
export {};
//# sourceMappingURL=IOType.d.ts.map