import { assert } from "../../../assert.js";
import { ReactiveTrigger } from "./ReactiveTrigger.js";

export class BlackboardTrigger {

    /**
     * @type {String|null}
     */
    code = null;

    /**
     *
     * @type {boolean}
     */
    isLinked = false;

    /**
     *
     * @type {Blackboard}
     */
    blackboard = null;

    /**
     *
     * @type {ReactiveTrigger}
     */
    trigger = null;

    /**
     *
     * @returns {ReactiveExpression}
     */
    getExpression() {
        return this.trigger.expression;
    }

    /**
     *
     * @returns {boolean}
     */
    isCompiled() {
        return this.trigger !== null;
    }

    compile() {
        assert.notEqual(this.isCompiled(), true, 'already compiled');

        this.trigger = new ReactiveTrigger(this.code);
    }

    /**
     *
     * @param {Blackboard} blackboard
     */
    link(blackboard) {
        assert.defined(blackboard, 'blackboard');

        if (this.isLinked) {
            //already linked

            if (this.blackboard !== blackboard) {
                throw new Error(`Already linked to another blackboard`);
            }

            return;
        }

        this.blackboard = blackboard;

        this.isLinked = true;

        if (!this.isCompiled()) {
            this.compile();
        }

        this.trigger.traverseReferences(this.connectReference, this);
    }

    unlink() {
        if (!this.isLinked) {
            //not linked
            return;
        }

        this.isLinked = false;

        this.trigger.traverseReferences(this.releaseReference, this);
    }

    /**
     * @private
     * @param {ReactiveReference} ref
     */
    connectReference(ref) {
        assert.defined(ref, 'ref');

        const value = this.blackboard.acquire(ref.name, ref.dataType);

        ref.connect(value);
    }

    /**
     * @private
     * @param {ReactiveReference} ref
     */
    releaseReference(ref) {
        assert.defined(ref, 'ref');

        ref.disconnect();

        this.blackboard.release(ref.name);
    }

}
