import { __awaiter, __generator } from "tslib";
import { getString } from '../str/str';
import { ControlEditionContext } from './control-edition-context';
import { DefaultValidationGuard } from './validation-guard';
/**
 * This is the base class for `FormControl`, `FormGroup`, and `FormArray`.
 *
 */
var AbstractControl = /** @class */ (function () {
    function AbstractControl(validators, options) {
        if (validators === void 0) { validators = []; }
        this.validators = validators;
        this.htmlElementAccessor = function () { return undefined; };
        this._validationGuard = DefaultValidationGuard;
        this._editionContext = ControlEditionContext.None;
        this._errors = [];
        this._waiting = false;
        this._enabled = true;
        this._readonly = false;
        this._pristine = true;
        this._touched = false;
        if (options) {
            if (options.validationGuard) {
                this._validationGuard = options.validationGuard;
            }
        }
    }
    Object.defineProperty(AbstractControl.prototype, "htmlElement", {
        get: function () {
            return this.htmlElementAccessor();
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AbstractControl.prototype, "pristine", {
        get: function () {
            return this._pristine;
        },
        enumerable: false,
        configurable: true
    });
    AbstractControl.prototype.hasError = function () {
        return this.errors.length > 0;
    };
    AbstractControl.prototype.hasErrorDeep = function () {
        return this.errorsDeep.length > 0;
    };
    Object.defineProperty(AbstractControl.prototype, "errorMessage", {
        /**
         * Gets the first error message, if any, of the current control errors.
         * Children errors are excluded.
         */
        get: function () {
            if (this.hasError()) {
                return getString(this.errors[0].message);
            }
            else {
                return '';
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AbstractControl.prototype, "errorMessageDeep", {
        /**
         * Gets the first error message, if any, of one of the current control and children control errors.
         */
        get: function () {
            if (this.hasErrorDeep()) {
                return getString(this.errorsDeep[0].message);
            }
            else {
                return '';
            }
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AbstractControl.prototype, "parent", {
        get: function () {
            return this._parent;
        },
        set: function (parent) {
            this._parent = parent;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * The submit method reset the edition context and runs all validations in
     * a downward manner from parents (FormGroup and FormArray) to childs (FormControl).
     */
    AbstractControl.prototype.submit = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                this._editionContext = ControlEditionContext.None;
                return [2 /*return*/];
            });
        });
    };
    AbstractControl.prototype.reset = function () {
        this._pristine = true;
        this.validators.forEach(function (v) { return v.lastCheck = undefined; });
        this._editionContext = ControlEditionContext.None;
        this.errors = [];
    };
    AbstractControl.prototype.upwardValueChanged = function () {
        this._pristine = false;
        if (!this._hasAnyControlsInError() && this.enabled && !this.readonly) {
            this.validate();
        }
        if (this._parent) {
            this._parent.upwardValueChanged();
        }
    };
    AbstractControl.prototype.validate = function () {
        var _this = this;
        this.validators.map(function (v) {
            if (v.async
                ||
                    _this._validationGuard(_this._editionContext, v.validationType)) {
                return;
            }
            var validationResult = v.validationFunction(_this);
            if (!(validationResult instanceof Promise)) {
                v.lastCheck = validationResult;
            }
            else {
                throw new Error('if you are using a async validation function  you must set the async flag to true');
            }
        });
        this._updateErrors();
    };
    AbstractControl.prototype.validateAsync = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, Promise.all(this.validators
                            .map(function (v) { return __awaiter(_this, void 0, void 0, function () {
                            var validationResult, _a;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        if (!v.async
                                            ||
                                                this._validationGuard(this._editionContext, v.validationType)) {
                                            return [2 /*return*/];
                                        }
                                        validationResult = v.validationFunction(this);
                                        if (!(validationResult instanceof Promise)) return [3 /*break*/, 2];
                                        this._waiting = true;
                                        _a = v;
                                        return [4 /*yield*/, validationResult];
                                    case 1:
                                        _a.lastCheck = _b.sent();
                                        this._waiting = false;
                                        return [3 /*break*/, 3];
                                    case 2: throw new Error('Async validation function should return a Promise<boolan>');
                                    case 3: return [2 /*return*/];
                                }
                            });
                        }); }))];
                    case 1:
                        _a.sent();
                        this._updateErrors();
                        return [2 /*return*/];
                }
            });
        });
    };
    AbstractControl.prototype.initEdition = function () {
        if (!this.enabled || this.readonly) {
            return;
        }
        if (this.errors.length > 0) {
            this._editionContext = ControlEditionContext.HasErrors;
        }
        else if (this.pristine) {
            this._editionContext = ControlEditionContext.Pristine;
        }
        else {
            this._editionContext = ControlEditionContext.Dirty;
        }
        if (this._parent) {
            this._parent.initEdition();
        }
    };
    AbstractControl.prototype.endEdition = function () {
        if (!this.enabled || this.readonly) {
            return;
        }
        this._editionContext = ControlEditionContext.None;
        this._updateErrors();
        if (!this.pristine && !this._hasAnyControlsInError()) {
            this.validate();
            this.validateAsync();
        }
        if (this._parent) {
            this._parent.endEdition();
        }
    };
    AbstractControl.prototype._updateErrors = function () {
        this.errors = this.validators.filter(function (v) { return v.lastCheck === false; }).map(function (v) { return v.error; });
    };
    AbstractControl.prototype._hasAnyControlsInError = function () {
        return false;
    };
    return AbstractControl;
}());
export { AbstractControl };
//# sourceMappingURL=abstract-control.js.map