(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./AtomBridge", "./AtomComponent", "./AtomOnce", "./AtomWatcher"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var AtomBridge_1 = require("./AtomBridge");
    var AtomComponent_1 = require("./AtomComponent");
    var AtomOnce_1 = require("./AtomOnce");
    var AtomWatcher_1 = require("./AtomWatcher");
    var PropertyBinding = /** @class */ (function () {
        function PropertyBinding(target, element, name, path, twoWays, valueFunc, source) {
            var _this = this;
            this.target = target;
            this.element = element;
            this.name = name;
            this.twoWays = twoWays;
            this.source = source;
            this.isTwoWaySetup = false;
            this.name = name;
            this.twoWays = twoWays;
            this.target = target;
            this.element = element;
            this.updaterOnce = new AtomOnce_1.AtomOnce();
            if (valueFunc) {
                if (typeof valueFunc !== "function") {
                    this.fromSourceToTarget = valueFunc.fromSource;
                    this.fromTargetToSource = valueFunc.fromTarget;
                }
                else {
                    this.fromSourceToTarget = valueFunc;
                }
            }
            this.watcher = new AtomWatcher_1.AtomWatcher(target, path, function () {
                var v = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    v[_i] = arguments[_i];
                }
                _this.updaterOnce.run(function () {
                    if (_this.disposed) {
                        return;
                    }
                    // set value
                    for (var _i = 0, v_1 = v; _i < v_1.length; _i++) {
                        var iterator = v_1[_i];
                        if (iterator === undefined) {
                            return;
                        }
                    }
                    var cv = _this.fromSourceToTarget ? _this.fromSourceToTarget.apply(_this, v) : v[0];
                    if (_this.target instanceof AtomComponent_1.AtomComponent) {
                        _this.target.setLocalValue(_this.element, _this.name, cv);
                    }
                    else {
                        _this.target[name] = cv;
                    }
                });
            }, source);
            this.path = this.watcher.path;
            if (this.target instanceof AtomComponent_1.AtomComponent) {
                this.target.runAfterInit(function () {
                    if (!_this.watcher) {
                        // this is disposed ...
                        return;
                    }
                    _this.watcher.init(true);
                    if (twoWays) {
                        _this.setupTwoWayBinding();
                    }
                });
            }
            else {
                this.watcher.init(true);
                if (twoWays) {
                    this.setupTwoWayBinding();
                }
            }
        }
        PropertyBinding.prototype.setupTwoWayBinding = function () {
            var _this = this;
            if (this.target instanceof AtomComponent_1.AtomComponent) {
                if (!(this.target.hasProperty(this.name) && !this.element || this.element === this.target.element)) {
                    // most likely it has change event..
                    var events = [];
                    if (typeof this.twoWays !== "boolean") {
                        events = this.twoWays;
                    }
                    this.twoWaysDisposable = AtomBridge_1.AtomBridge.instance.watchProperty(this.element, this.name, events, function (v) {
                        _this.setInverseValue(v);
                    });
                    return;
                }
            }
            var watcher = new AtomWatcher_1.AtomWatcher(this.target, [[this.name]], function () {
                var values = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    values[_i] = arguments[_i];
                }
                if (_this.isTwoWaySetup) {
                    _this.setInverseValue(values[0]);
                }
            });
            watcher.init(true);
            this.isTwoWaySetup = true;
            this.twoWaysDisposable = watcher;
        };
        PropertyBinding.prototype.setInverseValue = function (value) {
            var _this = this;
            if (!this.twoWays) {
                throw new Error("This Binding is not two ways.");
            }
            this.updaterOnce.run(function () {
                if (_this.disposed) {
                    return;
                }
                var first = _this.path[0];
                var length = first.length;
                var v = _this.target;
                var i = 0;
                var name;
                for (i = 0; i < length - 1; i++) {
                    name = first[i].name;
                    if (name === "this") {
                        v = _this.source || _this.target;
                    }
                    else {
                        v = v[name];
                    }
                    if (!v) {
                        return;
                    }
                }
                name = first[i].name;
                v[name] = _this.fromTargetToSource ? _this.fromTargetToSource.call(_this, value) : value;
            });
        };
        PropertyBinding.prototype.dispose = function () {
            if (this.twoWaysDisposable) {
                this.twoWaysDisposable.dispose();
                this.twoWaysDisposable = null;
            }
            this.watcher.dispose();
            this.disposed = true;
            this.watcher = null;
        };
        return PropertyBinding;
    }());
    exports.PropertyBinding = PropertyBinding;
});
//# sourceMappingURL=PropertyBinding.js.map