import { CommonModule } from '@angular/common';
import { Input, Directive, NgZone, ChangeDetectorRef, Optional, ContentChild, Component, ViewEncapsulation, ChangeDetectionStrategy, ContentChildren, Injectable, InjectionToken, Inject, Pipe, NgModule } from '@angular/core';
import { Subject, defer, of } from 'rxjs';
import { take, switchMap, takeUntil, filter } from 'rxjs/operators';
import { FormControl, NgForm, FormGroupDirective, Validators } from '@angular/forms';
import { trigger, transition } from '@angular/animations';
import { coerceNumberProperty, coerceBooleanProperty } from '@angular/cdk/coercion';
import { fadeOut, fadeIn } from '@ng-tangram/components/core';

class NtFormFieldControl {
    focus() { }
}

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
let NtFormLabelWidthDirective = class NtFormLabelWidthDirective {
    constructor() {
        this._widthChange = new Subject();
        this._width = 120;
    }
    get width() { return this._width; }
    set width(value) {
        this._width = coerceNumberProperty(value, 120);
    }
    get widthChange() { return this._widthChange.asObservable(); }
    ngOnChanges(changes) {
        const change = changes.width;
        if (change.currentValue !== change.previousValue) {
            this._widthChange.next(change.currentValue);
        }
    }
    ngOnDestroy() {
        this._widthChange.complete();
    }
};
__decorate([
    Input('ntFormLabelWidth')
], NtFormLabelWidthDirective.prototype, "width", null);
NtFormLabelWidthDirective = __decorate([
    Directive({
        selector: 'form[ntFormLabelWidth]',
    })
], NtFormLabelWidthDirective);

var __decorate$1 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
let NtFormOrientationDirective = class NtFormOrientationDirective {
    constructor() {
        this._orientationChange = new Subject();
    }
    get orientation() { return this._orientation; }
    set orientation(value) {
        this._orientation = value;
    }
    get orientationChange() {
        return this._orientationChange.asObservable();
    }
    ngOnChanges(changes) {
        const change = changes.orientation;
        if (change.currentValue !== change.previousValue) {
            this._orientationChange.next(change.currentValue);
        }
    }
    ngOnDestroy() {
        this._orientationChange.complete();
    }
};
__decorate$1([
    Input('ntFormOrientation')
], NtFormOrientationDirective.prototype, "orientation", null);
NtFormOrientationDirective = __decorate$1([
    Directive({
        selector: 'form[ntFormOrientation]',
    })
], NtFormOrientationDirective);

var __decorate$2 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
let NtFormFieldComponent = class NtFormFieldComponent {
    constructor(_ngZone, _changeDetectorRef, parentForm, parentFormGroup, _formLabelWidth, _formOrientation) {
        this._ngZone = _ngZone;
        this._changeDetectorRef = _changeDetectorRef;
        this._formLabelWidth = _formLabelWidth;
        this._formOrientation = _formOrientation;
        this._destroy = new Subject();
        this._markVisible = true;
        this._isUnsetedWidthValue = true;
        this._ngForm = null;
        this._labelStyles = {};
        this._groupStyles = {};
        this._invalid = false;
        this._labelVisible = true;
        this._labelWidth = 120;
        this.statusChanges = defer(() => {
            if (this.control && this.ngControl) {
                return this.ngControl.statusChanges ? this.ngControl.statusChanges : of(null);
            }
            return this._ngZone.onStable
                .asObservable()
                .pipe(take(1), switchMap(() => this.statusChanges));
        });
        this._ngForm = parentForm || parentFormGroup;
        if (this._formLabelWidth) {
            this._subscribeContainerWidthChange();
        }
        if (this._formOrientation) {
            this._subscribeContainerOrientationChange();
        }
        this.statusChanges
            .pipe(takeUntil(this._destroy))
            .subscribe(() => this._validate());
    }
    get labelVisible() { return this._labelVisible; }
    set labelVisible(value) {
        this._labelVisible = coerceBooleanProperty(value);
    }
    get labelWidth() { return this._labelWidth; }
    set labelWidth(value) {
        const coercedValue = coerceNumberProperty(value, 0);
        if (coercedValue > 0) {
            this._isUnsetedWidthValue = false;
            this._labelWidth = coercedValue;
        }
        else {
            this._isUnsetedWidthValue = true;
            this._labelWidth = 120;
        }
        this._setHorizontalStyles();
    }
    get orientation() { return this._orientation; }
    set orientation(value) {
        this._orientation = value;
        this._setHorizontalStyles();
    }
    get markVisible() { return this._markVisible; }
    set markVisible(value) {
        this._markVisible = coerceBooleanProperty(value);
    }
    get required() {
        if (this.ngControl &&
            this.ngControl.control &&
            this.ngControl.control.validator) {
            const control = new FormControl();
            const validateResult = this.ngControl.control.validator(control);
            return validateResult && validateResult.hasOwnProperty('required');
        }
        if (this.control) {
            return !!this.control.required;
        }
        return false;
    }
    get errors() {
        return this.control.ngControl ? this.control.ngControl.errors : null;
    }
    get ngControl() { return this.control ? this.control.ngControl : null; }
    ngAfterViewInit() {
        if (this._ngForm && this.ngControl) {
            this._ngForm.ngSubmit
                .pipe(takeUntil(this._destroy))
                .subscribe(() => this._validate());
        }
    }
    ngOnDestroy() {
        this._destroy.next();
        this._destroy.complete();
    }
    _clearValidateMessage() {
        this._invalid = false;
    }
    isHorizontal() {
        return this.orientation === 'horizontal';
    }
    isVertical() {
        return this.orientation === 'vertical';
    }
    _validate() {
        if (this.ngControl) {
            this._invalid = !!this.ngControl.invalid;
            this._changeDetectorRef.markForCheck();
        }
    }
    _subscribeContainerWidthChange() {
        this._formLabelWidth.widthChange.pipe(filter(() => this._isUnsetedWidthValue), takeUntil(this._destroy))
            .subscribe(width => {
            this._labelWidth = width;
            this._setHorizontalStyles();
        });
    }
    _subscribeContainerOrientationChange() {
        this._formOrientation.orientationChange
            .pipe(filter(() => !this._orientation), takeUntil(this._destroy))
            .subscribe(orientation => {
            this._orientation = orientation;
            this._setHorizontalStyles();
        });
    }
    _setHorizontalStyles() {
        if (this.labelWidth > 0 && this.isHorizontal()) {
            this._labelStyles['width.px'] = this.labelWidth;
            this._groupStyles['margin-left.px'] = this.labelWidth;
        }
        else {
            delete this._labelStyles['width.px'];
            delete this._groupStyles['margin-left.px'];
        }
    }
};
NtFormFieldComponent.ctorParameters = () => [
    { type: NgZone },
    { type: ChangeDetectorRef },
    { type: NgForm, decorators: [{ type: Optional }] },
    { type: FormGroupDirective, decorators: [{ type: Optional }] },
    { type: NtFormLabelWidthDirective, decorators: [{ type: Optional }] },
    { type: NtFormOrientationDirective, decorators: [{ type: Optional }] }
];
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "label", void 0);
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "labelVisible", null);
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "labelWidth", null);
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "messages", void 0);
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "orientation", null);
__decorate$2([
    Input()
], NtFormFieldComponent.prototype, "markVisible", null);
__decorate$2([
    ContentChild(NtFormFieldControl)
], NtFormFieldComponent.prototype, "control", void 0);
NtFormFieldComponent = __decorate$2([
    Component({
        selector: 'nt-form-field',
        template: `
    <label class="nt-form-label"
      *ngIf="labelVisible"
      [ngStyle]="_labelStyles"
      [class.required]="markVisible && required">
      {{label}}
    </label>
    <div class="nt-form-group" [ngStyle]="_groupStyles">
      <ng-content></ng-content>
      <span class="form-error is-visible" *ngIf="_invalid && errors" [@fade]="_invalid">
        {{ errors | formError:label:messages }}
      </span>
    </div>
  `,
        animations: [
            trigger('fade', [
                transition('* => false', fadeOut(.15)),
                transition('* => true', fadeIn(.15))
            ])
        ],
        encapsulation: ViewEncapsulation.None,
        changeDetection: ChangeDetectionStrategy.OnPush,
        host: {
            'class': 'nt-form-field',
            '[class.nt-form-error]': '_invalid',
            '[class.nt-form-horizontal]': 'isHorizontal()'
        }
    }),
    __param(2, Optional()),
    __param(3, Optional()),
    __param(4, Optional()),
    __param(5, Optional())
], NtFormFieldComponent);

var __decorate$3 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param$1 = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
let NtFormAutofocusDirective = class NtFormAutofocusDirective {
    constructor(form, formGroup) {
        this._destory = new Subject();
        this.formContainer = form || formGroup;
    }
    ngAfterContentInit() {
        if (this.formContainer) {
            this.formContainer.ngSubmit
                .pipe(takeUntil(this._destory))
                .subscribe(() => {
                const field = this.fields.find(field => !!field.ngControl && !!field.ngControl.invalid);
                if (field && field.control) {
                    field.control.focus();
                }
            });
        }
    }
    ngOnDestroy() {
        this._destory.next();
        this._destory.complete();
    }
};
NtFormAutofocusDirective.ctorParameters = () => [
    { type: NgForm, decorators: [{ type: Optional }] },
    { type: FormGroupDirective, decorators: [{ type: Optional }] }
];
__decorate$3([
    ContentChildren(NtFormFieldComponent, { descendants: true })
], NtFormAutofocusDirective.prototype, "fields", void 0);
NtFormAutofocusDirective = __decorate$3([
    Directive({
        selector: 'form[ntFormAutofocus]'
    }),
    __param$1(0, Optional()),
    __param$1(1, Optional())
], NtFormAutofocusDirective);

var __decorate$4 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const DEFAULT_TEMPLATES = {
    required: "请填写{0}",
    email: "{0}不是邮箱格式",
    min: "{0}必须输入大于{1}的数字",
    max: "{0}必须输入小于{1}的数字",
    pattern: "{0}不是合法的数据",
    maxlength: "{0}长度为最大{1}",
    minlength: "{0}长度为最小{1}",
    selection: '请选择{0}',
    upload: '请上传{0}',
    equalTo: '两次输入不一致',
    ltTo: '{0}的最小值应小于{1}',
    ltDateTo: '{0}应早于{1}',
    gtDateTo: '{0}应晚于{1}',
    unequalTo: '{0}必须和{1}不相同',
    intervalTo: '请输入正确区间值',
    notUnique: '{0}已存在',
    incorrect: '请输入正确{0}',
};
let NtFormValidationTransformer = class NtFormValidationTransformer {
    transform(errors, label, messages) {
        if (!errors) {
            return '';
        }
        const templates = Object.assign(Object.assign({}, DEFAULT_TEMPLATES), messages);
        if (errors.hasOwnProperty('required')) {
            if (errors.hasOwnProperty('selection')) {
                return this._format(templates['selection'], label);
            }
            else if (errors.hasOwnProperty('upload')) {
                return this._format(templates['upload'], label);
            }
            return this._format(templates['required'], label);
        }
        else if (errors.hasOwnProperty('email')) {
            return this._format(templates['email'], label);
        }
        else if (errors.hasOwnProperty('min')) {
            return this._format(templates['min'], label, errors.min.min);
        }
        else if (errors.hasOwnProperty('max')) {
            return this._format(templates['max'], label, errors.max.max);
        }
        else if (errors.hasOwnProperty('minlength')) {
            return this._format(templates['minlength'], label, errors.minlength.requiredLength);
        }
        else if (errors.hasOwnProperty('maxlength')) {
            return this._format(templates['maxlength'], label, errors.maxlength.requiredLength);
        }
        else if (errors.hasOwnProperty('pattern')) {
            return this._format(templates['pattern'], label);
        }
        else if (errors.hasOwnProperty('equalTo')) {
            return this._format(templates['equalTo'], label, errors.equalLabel);
        }
        else if (errors.hasOwnProperty('ltTo')) {
            return this._format(templates['ltTo'], label, errors.ltLabel);
        }
        else if (errors.hasOwnProperty('ltDateTo')) {
            return this._format(templates['ltDateTo'], label, errors.ltLabel);
        }
        else if (errors.hasOwnProperty('gtDateTo')) {
            return this._format(templates['gtDateTo'], label, errors.gtLabel);
        }
        else if (errors.hasOwnProperty('unequalTo')) {
            return this._format(templates['unequalTo'], label, errors.unequalLabel);
        }
        else if (errors.hasOwnProperty('intervalTo')) {
            return this._format(templates['intervalTo']);
        }
        else if (errors.hasOwnProperty('notUnique')) {
            return this._format(templates['notUnique'], label);
        }
        else if (errors.hasOwnProperty('incorrect')) {
            return this._format(templates['incorrect'], label);
        }
        else {
            return '';
        }
    }
    _format(template, ...args) {
        return template.replace(/\{(\d+)\}/g, function (match, number) {
            return typeof args[number] !== 'undefined' ? args[number] : match;
        });
    }
};
NtFormValidationTransformer = __decorate$4([
    Injectable()
], NtFormValidationTransformer);
const NT_VALIDATION_TRANSFOMER = new InjectionToken('nt-validation-transformer');

var __decorate$5 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param$2 = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
let NtFormErrorPipe = class NtFormErrorPipe {
    constructor(_transformer) {
        this._transformer = _transformer;
    }
    transform(value, ...args) {
        return this._transformer.transform(value, ...args);
    }
};
NtFormErrorPipe.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [NT_VALIDATION_TRANSFOMER,] }] }
];
NtFormErrorPipe = __decorate$5([
    Pipe({ name: 'formError' }),
    __param$2(0, Inject(NT_VALIDATION_TRANSFOMER))
], NtFormErrorPipe);

var __decorate$6 = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var NtFormsModule_1;
let NtFormsModule = NtFormsModule_1 = class NtFormsModule {
    static forRoot(transformer) {
        return {
            ngModule: NtFormsModule_1,
            providers: [
                { provide: NT_VALIDATION_TRANSFOMER, useClass: transformer || NtFormValidationTransformer }
            ]
        };
    }
};
NtFormsModule = NtFormsModule_1 = __decorate$6([
    NgModule({
        imports: [CommonModule],
        exports: [
            NtFormFieldComponent,
            NtFormAutofocusDirective,
            NtFormLabelWidthDirective,
            NtFormOrientationDirective,
            NtFormErrorPipe
        ],
        declarations: [
            NtFormFieldComponent,
            NtFormAutofocusDirective,
            NtFormLabelWidthDirective,
            NtFormOrientationDirective,
            NtFormErrorPipe
        ]
    })
], NtFormsModule);

function requiredSelection(control) {
    const errors = Validators.required(control);
    return errors && errors.required ? { required: true, selection: true } : null;
}
function requiredUpload(control) {
    const errors = Validators.required(control);
    return errors && errors.required ? { required: true, upload: true } : null;
}
function equalTo(equalControl, equalLabel) {
    let subscribe;
    return (control) => {
        if (!subscribe) {
            subscribe = equalControl.valueChanges
                .pipe(filter(() => control.touched))
                .subscribe(() => {
                control.updateValueAndValidity();
            });
        }
        const controlValue = control.value;
        return equalControl.value == controlValue ? null : { equalTo: true, equalLabel };
    };
}
function unequalTo(equalControl, unequalLabel) {
    let subscribe;
    return (control) => {
        if (!subscribe) {
            subscribe = equalControl.valueChanges
                .pipe(filter(() => control.touched))
                .subscribe(() => {
                control.updateValueAndValidity();
            });
        }
        const controlValue = control.value;
        return equalControl.value !== controlValue ? null : { unequalTo: true, unequalLabel };
    };
}
function interval(intervalLabel) {
    return (control) => {
        if (control.value) {
            const controlValue = control.value.split(/(\(|\)|\[|\]|,)/g);
            return Number(controlValue[2]) < Number(controlValue[4]) ? null : { intervalTo: true, intervalLabel };
        }
        return null;
    };
}
function ltTo(withControl, ltLabel) {
    let subscribe;
    return (control) => {
        if (!subscribe) {
            subscribe = withControl.valueChanges
                .pipe(filter(() => control.touched))
                .subscribe(() => {
                control.updateValueAndValidity();
            });
        }
        const controlValue = control.value;
        if (withControl.value) {
            return Number(controlValue) < Number(withControl.value) ? null : { ltTo: true, ltLabel };
        }
        return null;
    };
}
function ltDateTo(withControl, ltLabel, dateAdapter) {
    let subscribe;
    return (control) => {
        if (!subscribe) {
            subscribe = withControl.valueChanges.subscribe(() => {
                control.updateValueAndValidity();
            });
        }
        if (withControl.value && control.value) {
            return dateAdapter.compareDate(dateAdapter.deserialize(control.value), dateAdapter.deserialize(withControl.value)) < 0 ? null : { ltDateTo: true, ltLabel };
        }
        return null;
    };
}
function gtDateTo(withControl, gtLabel, dateAdapter) {
    let subscribe;
    return (control) => {
        if (!subscribe) {
            subscribe = withControl.valueChanges.subscribe(() => {
                control.updateValueAndValidity();
            });
        }
        if (withControl.value && control.value) {
            return dateAdapter.compareDate(dateAdapter.deserialize(control.value), dateAdapter.deserialize(withControl.value)) > 0 ? null : { gtDateTo: true, gtLabel };
        }
        return null;
    };
}

export { DEFAULT_TEMPLATES, NT_VALIDATION_TRANSFOMER, NtFormAutofocusDirective, NtFormErrorPipe, NtFormFieldComponent, NtFormFieldControl, NtFormLabelWidthDirective, NtFormOrientationDirective, NtFormValidationTransformer, NtFormsModule, equalTo, gtDateTo, interval, ltDateTo, ltTo, requiredSelection, requiredUpload, unequalTo };
//# sourceMappingURL=forms.js.map
