<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements.  See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership.  The ASF licenses this file
  ~ to you under the Apache License, Version 2.0 (the
  ~ "License"); you may not use this file except in compliance
  ~ with the License.  You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<nz-card nzTitle="Memory" nzSize="small" class="flink-memory-model">
  <nz-table
    nzBordered
    *ngIf="metrics"
    nzTemplateMode
    nzSize="small"
    [nzWidthConfig]="['220px', '200px', '200px', null]"
  >
    <thead>
      <tr>
        <th colspan="2" class="table-header">Flink Memory Model</th>
        <th class="table-header">
          Effective Configuration
          <i
            class="header-icon"
            nz-icon
            nz-tooltip
            nzTooltipTitle="This column shows the values that are actually used by Flink. These may differ from the configured values; Flink may adjust them to fit the actual setup, and automatically derives values that were not explicitly configured."
            nzType="info-circle"
          ></i>
        </th>
        <th class="table-header">Metric</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td rowspan="8" class="table-header">
          <img src="assets/images/memory-model.svg" alt="Memory model" />
        </td>
        <td class="table-header">Framework Heap</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.frameworkHeap | humanizeBytes }}</td>
        <td rowspan="2">
          <nz-progress
            nzSize="small"
            nzStrokeLinecap="square"
            [nzPercent]="
              +(
                (metrics['Status.JVM.Memory.Heap.Used'] / metrics['Status.JVM.Memory.Heap.Max']) *
                  100 | number: '1.0-2'
              )
            "
            nzStatus="normal"
          ></nz-progress>
          {{ metrics['Status.JVM.Memory.Heap.Used'] | humanizeBytes }} /
          {{ metrics['Status.JVM.Memory.Heap.Max'] | humanizeBytes }}
          <i
            nz-icon
            nz-tooltip
            nzTooltipTitle="The maximum heap displayed might differ from the configured values depending on the used GC algorithm for this process."
            nzType="info-circle"
          ></i>
        </td>
      </tr>
      <tr>
        <td class="table-header">Task Heap</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.taskHeap | humanizeBytes }}</td>
      </tr>
      <tr>
        <td class="table-header">Managed Memory</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.managedMemory | humanizeBytes }}</td>
        <td>
          <nz-progress
            nzSize="small"
            nzStrokeLinecap="square"
            [nzPercent]="
              +(
                (metrics['Status.Flink.Memory.Managed.Used'] /
                  metrics['Status.Flink.Memory.Managed.Total']) *
                  100 | number: '1.0-2'
              )
            "
            nzStatus="normal"
          ></nz-progress>
          {{ metrics['Status.Flink.Memory.Managed.Used'] | humanizeBytes }} /
          {{ metrics['Status.Flink.Memory.Managed.Total'] | humanizeBytes }}
        </td>
      </tr>
      <tr>
        <td class="table-header">Framework Off-Heap</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.frameworkOffHeap | humanizeBytes }}</td>
        <td rowspan="2">
          <i
            nz-icon
            nz-tooltip
            nzTooltipTitle="Metrics related to this configuration parameter cannot be monitored. Flink does not have full control over these memory pools."
            nzType="info-circle"
          ></i>
        </td>
      </tr>
      <tr>
        <td class="table-header">Task Off-Heap</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.taskOffHeap | humanizeBytes }}</td>
      </tr>
      <tr>
        <td class="table-header">Network</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.networkMemory | humanizeBytes }}</td>
        <td>
          <nz-progress
            nzSize="small"
            nzStrokeLinecap="square"
            [nzPercent]="
              +(
                (metrics['Status.Shuffle.Netty.UsedMemory'] /
                  metrics['Status.Shuffle.Netty.TotalMemory']) *
                  100 | number: '1.0-2'
              )
            "
            nzStatus="normal"
          ></nz-progress>
          {{ metrics['Status.Shuffle.Netty.UsedMemory'] | humanizeBytes }} /
          {{ metrics['Status.Shuffle.Netty.TotalMemory'] | humanizeBytes }}
        </td>
      </tr>
      <tr>
        <td class="table-header">JVM Metaspace</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.jvmMetaspace | humanizeBytes }}</td>
        <td>
          <nz-progress
            nzSize="small"
            nzStrokeLinecap="square"
            [nzPercent]="
              +(
                (metrics['Status.JVM.Memory.Metaspace.Used'] /
                  metrics['Status.JVM.Memory.Metaspace.Max']) *
                  100 | number: '1.0-2'
              )
            "
            nzStatus="normal"
          ></nz-progress>
          {{ metrics['Status.JVM.Memory.Metaspace.Used'] | humanizeBytes }} /
          {{ metrics['Status.JVM.Memory.Metaspace.Max'] | humanizeBytes }}
        </td>
      </tr>
      <tr>
        <td class="table-header">JVM Overhead</td>
        <td>{{ taskManagerDetail?.memoryConfiguration.jvmOverhead | humanizeBytes }}</td>
        <td>
          <i
            nz-icon
            nz-tooltip
            nzTooltipTitle="Metrics related to this configuration parameter cannot be monitored. Flink does not have full control over these memory pools."
            nzType="info-circle"
          ></i>
        </td>
      </tr>
    </tbody>
  </nz-table>
</nz-card>
<nz-card nzTitle="Advanced" nzSize="small" class="flink-memory-model">
  <div nz-row [nzGutter]="16">
    <div nz-col [nzSpan]="12">
      <nz-table
        nzBordered
        nzTitle="JVM (Heap/Non-Heap) Memory"
        [nzTemplateMode]="true"
        [nzFrontPagination]="false"
        [nzShowPagination]="false"
        [nzSize]="'small'"
        class="no-border"
      >
        <thead>
          <tr>
            <th>Type</th>
            <th>Committed</th>
            <th>Used</th>
            <th>Maximum</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><strong>Heap</strong></td>
            <td>{{ taskManagerDetail?.metrics.heapCommitted | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.heapUsed | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.heapMax | humanizeBytes }}</td>
          </tr>
          <tr>
            <td><strong>Non-Heap</strong></td>
            <td>{{ taskManagerDetail?.metrics.nonHeapCommitted | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.nonHeapUsed | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.nonHeapMax | humanizeBytes }}</td>
          </tr>
        </tbody>
      </nz-table>
    </div>
    <div nz-col [nzSpan]="12">
      <nz-table
        nzBordered
        nzTitle="Outside JVM Memory"
        [nzTemplateMode]="true"
        [nzFrontPagination]="false"
        [nzShowPagination]="false"
        [nzSize]="'small'"
        class="no-border"
      >
        <thead>
          <tr>
            <th>Type</th>
            <th>Count</th>
            <th>Used</th>
            <th>Capacity</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><strong>Direct</strong></td>
            <td>{{ taskManagerDetail?.metrics.directCount | number }}</td>
            <td>{{ taskManagerDetail?.metrics.directUsed | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.directMax | humanizeBytes }}</td>
          </tr>
          <tr>
            <td><strong>Mapped</strong></td>
            <td>{{ taskManagerDetail?.metrics.mappedCount | number }}</td>
            <td>{{ taskManagerDetail?.metrics.mappedUsed | humanizeBytes }}</td>
            <td>{{ taskManagerDetail?.metrics.mappedMax | humanizeBytes }}</td>
          </tr>
        </tbody>
      </nz-table>
    </div>
  </div>
  <div nz-row [nzGutter]="16" class="top-margin">
    <div nz-col [nzSpan]="12">
      <nz-table
        nzBordered
        nzTitle="Netty Shuffle Buffers"
        [nzTemplateMode]="true"
        [nzFrontPagination]="false"
        [nzShowPagination]="false"
        [nzSize]="'small'"
        class="no-border"
      >
        <thead>
          <tr>
            <th>Type</th>
            <th>Count</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td><strong>Available</strong></td>
            <td>{{ taskManagerDetail?.metrics.memorySegmentsAvailable | number }}</td>
          </tr>
          <tr>
            <td><strong>Total</strong></td>
            <td>{{ taskManagerDetail?.metrics.memorySegmentsTotal | number }}</td>
          </tr>
        </tbody>
      </nz-table>
    </div>
    <div nz-col [nzSpan]="12">
      <nz-table
        nzBordered
        nzTitle="Garbage Collection"
        [nzTemplateMode]="true"
        [nzFrontPagination]="false"
        [nzShowPagination]="false"
        [nzSize]="'small'"
        class="no-border"
      >
        <thead>
          <tr>
            <th>Collector</th>
            <th>Count</th>
            <th>Time</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let g of taskManagerDetail?.metrics.garbageCollectors">
            <td>
              <strong>{{ g.name }}</strong>
            </td>
            <td>{{ g.count | number }}</td>
            <td>{{ g.time | number }}</td>
          </tr>
        </tbody>
      </nz-table>
    </div>
  </div>
</nz-card>

<ng-template #tmResourceRow let-detail="detail" let-name="name" let-property="prop" let-unit="unit">
  <tr>
    <td>
      <strong>{{ name }}</strong>
    </td>
    <td>
      <nz-progress
        nzSize="small"
        nzStrokeLinecap="square"
        [nzPercent]="
          +(
            (detail?.freeResource[property] / detail?.totalResource[property]) * 100
            | number: '1.0-2'
          )
        "
        nzStatus="normal"
      ></nz-progress>
      {{ detail?.freeResource[property] | number }} /
      {{ detail?.totalResource[property] | number }} {{ unit }}
    </td>
  </tr>
</ng-template>

<nz-card nzTitle="Resources" nzSize="small" class="flink-memory-model">
  <nz-table
    nzBordered
    nzTitle="Unassigned resources"
    [nzTemplateMode]="true"
    [nzFrontPagination]="false"
    [nzShowPagination]="false"
    [nzSize]="'small'"
    class="no-border"
    [nzWidthConfig]="['200px', null]"
  >
    <thead>
      <tr>
        <th>Type</th>
        <th>Count</th>
      </tr>
    </thead>
    <tbody>
      <ng-container
        [ngTemplateOutlet]="tmResourceRow"
        [ngTemplateOutletContext]="{
          name: 'CPU',
          detail: taskManagerDetail,
          prop: 'cpuCores',
          unit: 'cores'
        }"
      ></ng-container>
      <ng-container
        [ngTemplateOutlet]="tmResourceRow"
        [ngTemplateOutletContext]="{
          name: 'Task Heap memory',
          detail: taskManagerDetail,
          prop: 'taskHeapMemory',
          unit: 'MB'
        }"
      ></ng-container>
      <ng-container
        [ngTemplateOutlet]="tmResourceRow"
        [ngTemplateOutletContext]="{
          name: 'Task Off-Heap memory',
          detail: taskManagerDetail,
          prop: 'taskOffHeapMemory',
          unit: 'MB'
        }"
      ></ng-container>
      <ng-container
        [ngTemplateOutlet]="tmResourceRow"
        [ngTemplateOutletContext]="{
          name: 'Managed memory',
          detail: taskManagerDetail,
          prop: 'managedMemory',
          unit: 'MB'
        }"
      ></ng-container>
      <ng-container
        [ngTemplateOutlet]="tmResourceRow"
        [ngTemplateOutletContext]="{
          name: 'Network memory',
          detail: taskManagerDetail,
          prop: 'networkMemory',
          unit: 'MB'
        }"
      ></ng-container>
    </tbody>
  </nz-table>
  <nz-table
    nzBordered
    nzTitle="Allocated slots"
    [nzTemplateMode]="true"
    [nzFrontPagination]="false"
    [nzShowPagination]="false"
    [nzSize]="'small'"
    class="no-border top-margin"
  >
    <thead>
      <tr>
        <th>#</th>
        <th>Job ID</th>
        <th>CPU (cores)</th>
        <th>Task Heap memory (MB)</th>
        <th>Task Off-Heap memory (MB)</th>
        <th>Managed memory (MB)</th>
        <th>Network memory (MB)</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let slot of taskManagerDetail?.allocatedSlots; let i = index">
        <td>
          <strong>{{ i | number }}</strong>
        </td>
        <td>{{ slot.jobId }}</td>
        <td>{{ slot.resource.cpuCores | number }}</td>
        <td>{{ slot.resource.taskHeapMemory | number }}</td>
        <td>{{ slot.resource.taskOffHeapMemory | number }}</td>
        <td>{{ slot.resource.managedMemory | number }}</td>
        <td>{{ slot.resource.networkMemory | number }}</td>
      </tr>
    </tbody>
  </nz-table>
</nz-card>
