text: /**
   * Use of this source code is governed by an MIT-style license that can be
   * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
   */
  
  import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewEncapsulation } from '@angular/core';
  import { NotificationConfig, NzConfigKey, NzConfigService } from 'ng-zorro-antd/core/config';
  import { toCssPixel } from 'ng-zorro-antd/core/util';
  
  import { NzMNContainerComponent } from 'ng-zorro-antd/message';
  import { Subject } from 'rxjs';
  import { takeUntil } from 'rxjs/operators';
  
  import { NzNotificationData, NzNotificationDataOptions } from './typings';
  
  const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'notification';
  
  const NZ_NOTIFICATION_DEFAULT_CONFIG: Required<NotificationConfig> = {
    nzTop: '24px',
    nzBottom: '24px',
    nzPlacement: 'topRight',
    nzDuration: 4500,
    nzMaxStack: 7,
    nzPauseOnHover: true,
    nzAnimate: true
  };
  
  @Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None,
    selector: 'nz-notification-container',
    exportAs: 'nzNotificationContainer',
    preserveWhitespaces: false,
    template: `
      <div class="ant-notification ant-notification-topLeft" [style.top]="top" [style.left]="'0px'">
        <nz-notification
          *ngFor="let instance of topLeftInstances"
          [instance]="instance"
          [placement]="config.nzPlacement"
          (destroyed)="remove($event.id, $event.userAction)"
        ></nz-notification>
      </div>
      <div class="ant-notification ant-notification-topRight" [style.top]="top" [style.right]="'0px'">
        <nz-notification
          *ngFor="let instance of topRightInstances"
          [instance]="instance"
          [placement]="config.nzPlacement"
          (destroyed)="remove($event.id, $event.userAction)"
        ></nz-notification>
      </div>
      <div class="ant-notification ant-notification-bottomLeft" [style.bottom]="bottom" [style.left]="'0px'">
        <nz-notification
          *ngFor="let instance of bottomLeftInstances"
          [instance]="instance"
          [placement]="config.nzPlacement"
          (destroyed)="remove($event.id, $event.userAction)"
        ></nz-notification>
      </div>
      <div class="ant-notification ant-notification-bottomRight" [style.bottom]="bottom" [style.right]="'0px'">
        <nz-notification
          *ngFor="let instance of bottomRightInstances"
          [instance]="instance"
          [placement]="config.nzPlacement"
          (destroyed)="remove($event.id, $event.userAction)"
        ></nz-notification>
      </div>
    `
  })
  export class NzNotificationContainerComponent extends NzMNContainerComponent {
    bottom?: string | null;
    top?: string | null;
    config!: Required<NotificationConfig>; // initialized by parent class constructor
    instances: Array<Required<NzNotificationData>> = [];
    topLeftInstances: Array<Required<NzNotificationData>> = [];
    topRightInstances: Array<Required<NzNotificationData>> = [];
    bottomLeftInstances: Array<Required<NzNotificationData>> = [];
    bottomRightInstances: Array<Required<NzNotificationData>> = [];
  
    constructor(cdr: ChangeDetectorRef, nzConfigService: NzConfigService) {
      super(cdr, nzConfigService);
    }
  
    create(notification: NzNotificationData): Required<NzNotificationData> {
      const noti = this.onCreate(notification);
      const key = noti.options.nzKey;
      const notificationWithSameKey = this.instances.find(
        msg => msg.options.nzKey === (notification.options as Required<NzNotificationDataOptions>).nzKey
      );
      if (key && notificationWithSameKey) {
        this.replaceNotification(notificationWithSameKey, noti);
      } else {
        if (this.instances.length >= this.config.nzMaxStack) {
          this.instances = this.instances.slice(1);
        }
        this.instances = [...this.instances, noti];
      }
  
      this.readyInstances();
  
      return noti;
    }
  
    protected onCreate(instance: NzNotificationData): Required<NzNotificationData> {
      instance.options = this.mergeOptions(instance.options);
      instance.onClose = new Subject<boolean>();
      instance.onClick = new Subject<MouseEvent>();
      return instance as Required<NzNotificationData>;
    }
  
    protected subscribeConfigChange(): void {
      this.nzConfigService
        .getConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME)
        .pipe(takeUntil(this.destroy$))
        .subscribe(() => this.updateConfig());
    }
  
    protected updateConfig(): void {
      this.config = {
        ...NZ_NOTIFICATION_DEFAULT_CONFIG,
        ...this.config,
        ...this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME)
      };
  
      this.top = toCssPixel(this.config.nzTop!);
      this.bottom = toCssPixel(this.config.nzBottom!);
  
      this.cdr.markForCheck();
    }
  
    private replaceNotification(old: NzNotificationData, _new: NzNotificationData): void {
      old.title = _new.title;
      old.content = _new.content;
      old.template = _new.template;
      old.type = _new.type;
      old.options = _new.options;
    }
  
    protected readyInstances(): void {
      this.topLeftInstances = this.instances.filter(m => m.options.nzPlacement === 'topLeft');
      this.topRightInstances = this.instances.filter(m => m.options.nzPlacement === 'topRight' || !m.options.nzPlacement);
      this.bottomLeftInstances = this.instances.filter(m => m.options.nzPlacement === 'bottomLeft');
      this.bottomRightInstances = this.instances.filter(m => m.options.nzPlacement === 'bottomRight');
  
      this.cdr.detectChanges();
    }
  
    protected mergeOptions(options?: NzNotificationDataOptions): NzNotificationDataOptions {
      const { nzDuration, nzAnimate, nzPauseOnHover, nzPlacement } = this.config;
      return { nzDuration, nzAnimate, nzPauseOnHover, nzPlacement: nzPlacement, ...options };
    }
  }
  