linked-value.ts 7.71 KiB
import { Nub } from "./nub";
import { ParamDefinition } from "./param/param-definition";
import { INamedIterableValues } from "./param/param-value-iterator";
import { ParamValueMode } from "./param/param-value-mode";
import { ParamValues } from "./param/param-values";
export class LinkedValue {
    /** linked value metadata (ex: calculator title for GUI) */
    public meta: any;
    /** target Nub */
    private _nub: Nub;
    /** target value : ParamDefinition (possibly in CALC mode) | undefined (ExtraResults) */
    private _element: INamedIterableValues;
    /** parameter / result symbol (ex: "Q") */
    private _symbol: string;
    /** magic param values: proxy to target when target is a not a result, handcrafted fake object otherwise */
    private _paramValues: ParamValues;
    constructor(nub: Nub, element: INamedIterableValues, symbol: string, meta: any = {}) {
        this._nub = nub;
        this._element = element;
        this._symbol = symbol;
        this.meta = meta;
    public get nub() { return this._nub; }
    public get element() { return this._element; }
    public get symbol() { return this._symbol; }
    /**
     * Returns true if targetted value is a ParamDefinition (in CALC mode or not),
     * and not an extra result
    public isParameter(): boolean {
        return (this.element instanceof ParamDefinition);
    /**
     * Returns true if targetted value is a ParamDefinition in CALC mode
     * (might not have any value yet)
    public isResult(): boolean {
        return (
            this.isParameter()
            && (this.element as ParamDefinition).valueMode === ParamValueMode.CALCUL
    /**
     * Returns true if targetted value is a ParamDefinition in CALC mode,
     * or in LINK mode targetting a result (might not have any value yet)
    public isCalculated(): boolean {
        return (
            this.isResult()
            || this.isExtraResult()
            || (
                this.isParameter()
                && (this.element as ParamDefinition).valueMode === ParamValueMode.LINK
                && (this.element as ParamDefinition).referencedValue.isCalculated() // recursion
    /**
     * Returns true if targetted value is an extra result
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* (might not have any value yet) */ public isExtraResult(): boolean { return ( this.nub !== undefined && this.symbol !== undefined && ! this.isParameter() ); } /** * Returns true if v and the current objects have the same : * - Nub UID * - symbol * - value type (Parameter / Result) * (ignores metadata) * @param v */ public equals(v: LinkedValue): boolean { return ( v && (v.nub.uid === this.nub.uid) && (v.symbol === this.symbol) && ( (v.element === undefined && this.element === undefined) || ( v.element !== undefined && this.element !== undefined && v.element.constructor.name === this.element.constructor.name ) ) ); } /** * Returs the ParamValues for the linked Parameter if any, or a * fake ParamValues object if the targetted element is a Result * or ExtraResults. * If target is a result and triggerChainComputation is true, * triggers a chain computation to obtain the result */ public getParamValues(triggerChainComputation: boolean = false): ParamValues { let ret: ParamValues; // trigger computation ? if ( (this.isExtraResult() || this.isResult()) && triggerChainComputation ) { this.nub.CalcSerie(); } if (this.isParameter()) { const targetParam = (this.element as ParamDefinition); // target might be in CALC mode if (targetParam.valueMode === ParamValueMode.CALCUL) { // if already computed, expose handmade fake param values for iterability if (this.nub.result) { if (! this._paramValues) { this._paramValues = new ParamValues(); // populate if (targetParam.hasMultipleValues) { const multipleRes = this.nub.result.getCalculatedValues(); this._paramValues.setValues(multipleRes); } else { const singleRes = this.nub.result.vCalc; this._paramValues.setValues(singleRes); } }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
// return local cache ret = this._paramValues; } else { throw new Error("LinkedValue.getParamValues() - result not available"); } } else { // simple proxy to target parameter values; if target parameter is // also a LINK, ParamDefinition.paramValues will recursively call // LinkedValue.getParamValues() (this method) ret = targetParam.paramValues; } } else if (this.isExtraResult()) { // is result available ? if (this.nub.result) { // expose handmade fake param values for iterability if (! this._paramValues) { this._paramValues = new ParamValues(); // populate if (this.nub.resultHasMultipleValues()) { const multipleExtraRes = this.nub.result.getExtraResults(this.symbol); this._paramValues.setValues(multipleExtraRes); } else { const singleExtraRes = this.nub.result.getExtraResult(this.symbol); this._paramValues.setValues(singleExtraRes); } } // return local cache ret = this._paramValues; } else { throw new Error("LinkedValue.getParamValues() - extra result not available"); } } else { throw new Error("LinkedValue.getParamValues() - cannot determine nature of target"); } return ret; } /** * Returns the single value of this.paramValues; triggers a chain computation * if required to obtain ParamValues */ public getValue(triggerChainComputation: boolean = false) { const pv = this.getParamValues(triggerChainComputation); return pv.singleValue; } /** * Returns true if * - a parameter is targetted and it has multiple values * - a result / extra result is targetted and it has more than 1 value */ public hasMultipleValues(): boolean { if (this.isParameter()) { // possibly in CALC mode, but ParamDefinition.hasMultipleValues takes care of it return (this.element as ParamDefinition).hasMultipleValues; } else if (this.isResult() || this.isExtraResult()) { // guess if parent Nub has any variating parameter (linked or not) return this.nub.resultHasMultipleValues(); } return false; } /** * Returns true if target value is available */ public isDefined() { if (this.isExtraResult()) {
211212213214215216217218219220221222223224225
return (this.nub.result !== undefined); } else { return (this.element as ParamDefinition).isDefined; } } /** * When invalidating a Nub's result, parameters pointing to this result should * invalidate their proxy paramValues too */ public invalidateParamValues() { this._paramValues = undefined; } }