import { ParamValues } from "../param/param-values";
import { Result } from "..";

/**
 * objet (paramètre ou résultat) dont les valeurs sont référençables pour réutilisation
 * (d'une calculette sur une autre par ex)
 */
export interface IReferencedObject {
    /**
     * getter des valeurs
     * @param desc : description sous forme symbolique
     */
    getReferencedParamValues(desc: string): ParamValues;

    /**
     * getter du résultat
     * @param desc : description sous forme symbolique
     */
    getReferencedResult(desc?: string): Result;

    /**
     * getter du résultat complémentaire
     * @param desc : description sous forme symbolique
     */
    getReferencedExtraResult(desc: string): any;

    /**
     * itérateur sur les valeurs
     */
    getReferencedValuesIterator(desc: string): IterableIterator<number>;
}

/**
 * référence vers un objet contenant une valeur vers laquelle on crée un lien
 */
export interface IObjectReference {
    /**
     * définition de la valeur référencée dans l'objet
     * @param target objet contenant la valeur qu'on va référencer
     * @param desc : description de la valeur pointée sous forme symbolique. Exemples : Q, <n° d'ouvrage>.Z1
     */
    defineReference(target: IReferencedObject, desc: string): void;

    /**
     * description symbolique de la référence
     */
    readonly referenceDesc: string;

    /**
     * true si la référence a été définie
     */
    readonly isReferenceDefined: boolean;

    /**
     * instance de ParamValues référencée
     */
    readonly referencedParamValues: ParamValues;

    /**
     * instance de Result référencée
     */
    readonly referencedResult: Result;

    /**
     * instance de résultat complémentaire référencée
     */
    readonly referencedExtraResult: any;

    /**
     * itérateur sur les valeurs référencées
     */
    readonly referencedValuesIterator: IterableIterator<number>;
}

/**
 * implémentation par défaut de IObjectReference
 */
export class ObjectReference implements IObjectReference {
    private _referencedObject: IReferencedObject;

    private _refDefinition: string;

    public defineReference(target: IReferencedObject, desc: string) {
        this._referencedObject = target;
        this._refDefinition = desc;
    }

    /**
     * description symbolique de la référence
     */
    public get referenceDesc(): string {
        return this._refDefinition;
    }

    public get isReferenceDefined(): boolean {
        return this._referencedObject !== undefined && this._refDefinition !== undefined;
    }

    /**
     * objet référencé
     */
    public get referencedObject(): IReferencedObject {
        return this._referencedObject;
    }

    /**
     * instance de ParamValues référencée
     */
    public get referencedParamValues(): ParamValues {
        if (this._referencedObject === undefined)
            return undefined;
        return this._referencedObject.getReferencedParamValues(this._refDefinition);
    }

    /**
     * instance de Result référencée
     */
    public get referencedResult(): Result {
        if (this._referencedObject === undefined)
            return undefined;
        return this._referencedObject.getReferencedResult(this._refDefinition);
    }

    /**
     * instance de résultat complémentaire référencée
     */
    public get referencedExtraResult(): any {
        if (this._referencedObject === undefined)
            return undefined;
        return this._referencedObject.getReferencedExtraResult(this._refDefinition);
    }

    /**
     * itérateur sur les valeurs référencées
     */
    public get referencedValuesIterator(): IterableIterator<number> {
        return this._referencedObject.getReferencedValuesIterator(this._refDefinition);
    }
}