import _ from 'lodash';
import '../../../../assert/js/assert.js';
import '../../../../globals.js';
// Copyright 2021-2024, University of Colorado Boulder
/**
 * A configurable cell containing a Node used for GridConstraint layout
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */
import optionize from '../../../../phet-core/js/optionize.js';
import Orientation from '../../../../phet-core/js/Orientation.js';
import OrientationPair from '../../../../phet-core/js/OrientationPair.js';
import { GRID_CONFIGURABLE_OPTION_KEYS, GridConfigurable, MarginLayoutCell, scenery } from '../../imports.js';
const GRID_CELL_KEYS = [
    ...GRID_CONFIGURABLE_OPTION_KEYS,
    'row',
    'column',
    'horizontalSpan',
    'verticalSpan'
];
export default class GridCell extends GridConfigurable(MarginLayoutCell) {
    /**
     * (scenery-internal)
     */
    constructor(constraint, node, proxy) {
        super(constraint, node, proxy);
        this.gridConstraint = constraint;
        this.setOptions(node.layoutOptions);
        this.onLayoutOptionsChange(true);
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveXAlign() {
        return this._xAlign !== null ? this._xAlign : this.gridConstraint._xAlign;
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveYAlign() {
        return this._yAlign !== null ? this._yAlign : this.gridConstraint._yAlign;
    }
    /**
     * (scenery-internal)
     */
    getEffectiveAlign(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.effectiveXAlign : this.effectiveYAlign;
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveXGrow() {
        return this._xGrow !== null ? this._xGrow : this.gridConstraint._xGrow;
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveYGrow() {
        return this._yGrow !== null ? this._yGrow : this.gridConstraint._yGrow;
    }
    /**
     * (scenery-internal)
     */
    getEffectiveGrow(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.effectiveXGrow : this.effectiveYGrow;
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveXStretch() {
        return this._xStretch !== null ? this._xStretch : this.gridConstraint._xStretch;
    }
    /**
     * Return the used value, with this cell's value taking precedence over the constraint's default
     * (scenery-internal)
     */
    get effectiveYStretch() {
        return this._yStretch !== null ? this._yStretch : this.gridConstraint._yStretch;
    }
    /**
     * (scenery-internal)
     */
    getEffectiveStretch(orientation) {
        return orientation === Orientation.HORIZONTAL ? this.effectiveXStretch : this.effectiveYStretch;
    }
    onLayoutOptionsChange(isInitial = false) {
        this.setOptions(this.node.layoutOptions);
        super.onLayoutOptionsChange();
        if (!isInitial) {
            this.gridConstraint.updateLayoutAutomatically();
        }
    }
    setOptions(providedOptions) {
        // We'll have defaults for cells (the horizontalSpan/verticalSpan are especially relevant)
        const options = optionize()({
            column: 0,
            row: 0,
            horizontalSpan: 1,
            verticalSpan: 1
        }, providedOptions);
        assert && Object.keys(options).forEach(key => {
            assert && assert(GRID_CELL_KEYS.includes(key) || key === 'isSeparator', `Cannot provide key ${key} to a GridCell's layoutOptions. Perhaps this is a Flow-style layout option?`);
        });
        assert && assert(typeof options.column === 'number' && Number.isInteger(options.column) && isFinite(options.column) && options.column >= 0);
        assert && assert(typeof options.row === 'number' && Number.isInteger(options.row) && isFinite(options.row) && options.row >= 0);
        assert && assert(typeof options.horizontalSpan === 'number' && Number.isInteger(options.horizontalSpan) && isFinite(options.horizontalSpan) && options.horizontalSpan >= 1);
        assert && assert(typeof options.verticalSpan === 'number' && Number.isInteger(options.verticalSpan) && isFinite(options.verticalSpan) && options.verticalSpan >= 1);
        // Clear options that are not provided in the mutate options (but if they are present, do NOT clear, so we avoid
        // more potential for infinite loops)
        this.setConfigToInherit(options);
        this.position = new OrientationPair(options.column, options.row);
        this.size = new OrientationPair(options.horizontalSpan, options.verticalSpan);
        this.mutateConfigurable(options);
    }
    /**
     * Whether this cell contains the given row/column (based on the orientation). Due to horizontalSpan/verticalSpan of the cell,
     * this could be true for multiple indices.
     * (scenery-internal)
     */
    containsIndex(orientation, index) {
        const position = this.position.get(orientation);
        const size = this.size.get(orientation);
        return index >= position && index < position + size;
    }
    /**
     * Whether this cell contains the given row.
     * (scenery-internal)
     */
    containsRow(row) {
        return this.containsIndex(Orientation.VERTICAL, row);
    }
    /**
     * Whether this cell contains the given column.
     * (scenery-internal)
     */
    containsColumn(column) {
        return this.containsIndex(Orientation.HORIZONTAL, column);
    }
    /**
     * Returns the row/column indices that this cell spans (based on the orientation)
     * (scenery-internal)
     */
    getIndices(orientation) {
        const position = this.position.get(orientation);
        const size = this.size.get(orientation);
        return _.range(position, position + size);
    }
}
scenery.register('GridCell', GridCell);
//# sourceMappingURL=GridCell.js.map