
import { TransactionImpl } from '../transaction.js';
import { BaseObservable } from './baseObservable.js';
import '../../errors.js';
import { strictEquals } from '../../equals.js';
import '../../event.js';
import '../../lifecycle.js';
import { DebugNameData } from '../debugName.js';
import { getLogger } from '../logging/logging.js';

function observableValue(nameOrOwner, initialValue) {
    let debugNameData;
    if (typeof nameOrOwner === 'string') {
        debugNameData = ( new DebugNameData(undefined, nameOrOwner, undefined));
    }
    else {
        debugNameData = ( new DebugNameData(nameOrOwner, undefined, undefined));
    }
    return ( new ObservableValue(debugNameData, initialValue, strictEquals));
}
class ObservableValue extends BaseObservable {
    get debugName() {
        return this._debugNameData.getDebugName(this) ?? 'ObservableValue';
    }
    constructor(_debugNameData, initialValue, _equalityComparator) {
        super();
        this._debugNameData = _debugNameData;
        this._equalityComparator = _equalityComparator;
        this._value = initialValue;
        getLogger()?.handleObservableUpdated(this, { hadValue: false, newValue: initialValue, change: undefined, didChange: true, oldValue: undefined });
    }
    get() {
        return this._value;
    }
    set(value, tx, change) {
        if (change === undefined && this._equalityComparator(this._value, value)) {
            return;
        }
        let _tx;
        if (!tx) {
            tx = _tx = ( new TransactionImpl(() => { }, () => `Setting ${this.debugName}`));
        }
        try {
            const oldValue = this._value;
            this._setValue(value);
            getLogger()?.handleObservableUpdated(this, { oldValue, newValue: value, change, didChange: true, hadValue: true });
            for (const observer of this._observers) {
                tx.updateObserver(observer, this);
                observer.handleChange(this, change);
            }
        }
        finally {
            if (_tx) {
                _tx.finish();
            }
        }
    }
    toString() {
        return `${this.debugName}: ${this._value}`;
    }
    _setValue(newValue) {
        this._value = newValue;
    }
    debugGetState() {
        return {
            value: this._value,
        };
    }
    debugSetValue(value) {
        this._value = value;
    }
}
function disposableObservableValue(nameOrOwner, initialValue) {
    let debugNameData;
    if (typeof nameOrOwner === 'string') {
        debugNameData = ( new DebugNameData(undefined, nameOrOwner, undefined));
    }
    else {
        debugNameData = ( new DebugNameData(nameOrOwner, undefined, undefined));
    }
    return ( new DisposableObservableValue(debugNameData, initialValue, strictEquals));
}
class DisposableObservableValue extends ObservableValue {
    _setValue(newValue) {
        if (this._value === newValue) {
            return;
        }
        if (this._value) {
            this._value.dispose();
        }
        this._value = newValue;
    }
    dispose() {
        this._value?.dispose();
    }
}

export { DisposableObservableValue, ObservableValue, disposableObservableValue, observableValue };
