"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Pin = void 0;
const _1 = require("./Class/$");
class Pin extends _1.$ {
    constructor({ data, constant, ignored, ref } = {}, $system) {
        super($system);
        this.__ = ['V', 'PI'];
        this._constant = false;
        this._ignored = false;
        this._ref = false;
        this._invalid = false;
        this._idle = true;
        this._register = undefined;
        this._embodied = false;
        this._embody = (data) => {
            if (this._ref) {
                this.__embody(data);
            }
            return data;
        };
        this.__embody = (data) => {
            if (data instanceof Function) {
                this._embodied = true;
                data = new data(this.__system);
            }
            if (data instanceof _1.$) {
                if (data.__.includes('U')) {
                    ;
                    data.play();
                }
                data.register();
                if (data.__.includes('G')) {
                    this._unlisten = data.addListener('edit', () => {
                        this.emit('edit', data);
                    });
                }
            }
            return data;
        };
        this._disembody = (data) => {
            if (this._ref) {
                if (this._unlisten) {
                    this._unlisten();
                    this._unlisten = undefined;
                }
                if (data instanceof _1.$) {
                    data.unregister();
                }
                if (this._embodied) {
                    data.unregister();
                    data.destroy();
                    data = data.constructor;
                    this._embodied = false;
                }
            }
            return data;
        };
        if (data !== undefined) {
            this._idle = false;
        }
        this._register = data;
        this._constant = constant || false;
        this._ignored = ignored || false;
        this._ref = ref || false;
        if (this._ref) {
            this._push = this._push_ref;
        }
        else {
            this._push = this._push_data;
        }
    }
    take(propagate = true) {
        const data = this._register;
        if (this._register !== undefined) {
            this._disembody(data);
            this._register = undefined;
            if (propagate) {
                this.emit('drop', data);
            }
        }
        this.end();
        return data;
    }
    invalidate() {
        const data = this._register;
        if (data !== undefined) {
            this._disembody(data);
            if (!this._invalid) {
                this._invalid = true;
                this._idle = true;
                this.emit('invalid');
            }
        }
    }
    start() {
        if (this._idle) {
            this._idle = false;
            this.emit('start');
        }
    }
    end() {
        if (this._register === undefined && !this._idle) {
            this._idle = true;
            this.emit('end');
        }
    }
    pull() {
        const data = this._register;
        if (data !== undefined) {
            if (this._constant) {
                this.emit('_data', data);
            }
            else {
                this.take();
            }
        }
        return data;
    }
    push(data, backpropagation = false, propagate = true) {
        this._push(data, backpropagation, propagate);
    }
    _push_data(data, backpropagation = false, propagate = true) {
        this.invalidate();
        this._invalid = false;
        this.start();
        this._register = data;
        if (propagate) {
            this.emit('data', data, backpropagation);
        }
        if (this._ignored && !this._constant) {
            this.take();
        }
    }
    _push_ref(data, backpropagation = false, propagate = true) {
        this.invalidate();
        this._invalid = false;
        this.start();
        data = this.__embody(data);
        this._register = data;
        if (propagate) {
            this.emit('data', data, backpropagation);
        }
    }
    peak() {
        return this._register;
    }
    empty() {
        return this._register === undefined;
    }
    active() {
        return !this.empty();
    }
    ignored(value) {
        if (value !== undefined) {
            this._ignored = value;
            if (this._ignored && !this._constant && !this._ref) {
                this.take();
            }
            this.emit('ignored', this._ignored);
        }
        return this._ignored;
    }
    ref(value) {
        if (value !== undefined) {
            if (this._register) {
                if (value && !this._ref) {
                    this._register = this._embody(this._register);
                }
                else if (!value && this._ref) {
                    this._register = this._disembody(this._register);
                }
            }
            this._ref = value;
            this.emit('ref', this._ref);
        }
        return this._ref;
    }
    constant(value) {
        if (value !== undefined) {
            this._constant = value;
        }
        return this._constant;
    }
    invalid() {
        return this._invalid;
    }
    embodied() {
        return this._embodied;
    }
    snapshot() {
        return {
            _register: this._register instanceof _1.$ ? undefined : this._register,
            ...(this._invalid ? { _invalid: true } : {}),
            ...(this._constant ? { _constant: true } : {}),
            ...(this._ignored ? { _ignored: true } : {}),
            ...(this._idle ? {} : { _idle: false }),
        };
    }
    restore(state) {
        const { _register, _invalid, _constant, _ignored, _idle } = state;
        this._register = _register;
        this._invalid = _invalid;
        this._constant = _constant;
        this._ignored = _ignored;
        this._idle = _idle;
        if (_register instanceof _1.$) {
            this.emit('_data', _register);
        }
    }
    read() {
        return this._register;
    }
    write(data) {
        this.push(data);
    }
}
exports.Pin = Pin;
//# sourceMappingURL=Pin.js.map