<app-breadcrumbs [items]="breadcrumbs">
    <div page-help>
        <p>
            This page displays a list of all machines that have been configured in Stork. It allows adding new machines
            as well as removing them.
        </p>
        <p>
            If <em>Show Unauthorized</em> is toggled on, the list will show unauthorized machines. They were registered
            using the agent token-based registration method. To authorize a machine, click action menu button and then
            <em>Authorize</em>.
        </p>
    </div>
</app-breadcrumbs>

<p-dialog
    header="Change Machine Address"
    [(visible)]="changeMachineAddressDlgVisible"
    [style]="{ 'max-width': '100rem' }"
>
    <p style="padding-bottom: 1em">
        Stork server will be using the new address and/or port to communicate with this machine. Please ensure that the
        agent running on the machine is using this new address and/or port to avoid communication problems.
    </p>
    <div>
        Address:
        <input
            type="text"
            style="width: 100%"
            pInputText
            [(ngModel)]="machineAddress"
            id="change-machine-address"
            (keyup)="keyUpMachineDlg($event, machineTab)"
        />
    </div>
    <div style="margin-top: 10px">
        Port:
        <input
            type="text"
            style="width: 100%"
            placeholder="8080"
            pInputText
            [(ngModel)]="agentPort"
            id="change-machine-port"
            (keyup)="keyUpMachineDlg($event, machineTab)"
        />
    </div>
    <p-footer>
        <button
            type="button"
            (click)="cancelMachineDialog()"
            pButton
            icon="pi pi-times"
            label="Cancel"
            id="cancel-machine-edit-button"
        ></button>
        <button
            type="button"
            (click)="saveMachine(machineTab)"
            pButton
            icon="pi pi-check"
            label="Change"
            id="change-machine-button"
            class="p-button-warning"
        ></button>
    </p-footer>
</p-dialog>

<p-dialog header="Agent Installation Instructions" [(visible)]="displayAgentInstallationInstruction">
    <p style="margin: 10px 10px 10px 0; max-width: 38em">
        Copy these commands and paste them into a terminal on a machine where Stork Agent is going to be installed.
        <br />
        For more details check
        <a target="_blank" routerLink="/assets/arm/install.html#installing-from-packages"
            >the Stork Agent Installation instructions <i class="pi pi-external-link"></i></a
        >.
    </p>
    <div style="display: flex; align-items: flex-start; margin-bottom: 10px">
        <textarea class="monospace agent-install-cmds" readonly="" rows="3" #agentInstallationText>
wget {{ getBaseUrl() }}/stork-install-agent.sh
chmod a+x stork-install-agent.sh
sudo ./stork-install-agent.sh</textarea
        >
        <button
            type="button"
            (click)="copyToClipboard(agentInstallationText)"
            pButton
            icon="pi pi-copy"
            pTooltip="Copy commands to clipboard"
            class="flex-none"
        ></button>
    </div>
    <p style="margin: 10px 10px 10px 0; max-width: 38em">
        During agent installation you will be prompted for a server token.
    </p>
    <p style="margin: 10px 10px 10px 0; max-width: 40em">
        <b>Server token</b> value is
        <input [value]="serverToken" class="monospace server-token" size="32" readonly="" #serverTokenInput />

        <button
            type="button"
            (click)="copyToClipboard(serverTokenInput)"
            pButton
            icon="pi pi-copy"
            pTooltip="Copy server token to clipboard"
            style="margin-right: 6px"
        ></button>

        <button
            type="button"
            pButton
            icon="pi pi-refresh"
            label="Regenerate"
            pTooltip="If the server token has been compromised then regenerate it."
            class="p-button-secondary"
            (click)="regenerateServerToken()"
        ></button>
    </p>
    <p style="margin: 0 10px 10px 0; max-width: 38em">
        Providing the token will cause the new machine to be automatically added and authorized in the Stork Server.
    </p>
    <p style="margin: 0 10px 10px 0; max-width: 38em">
        If no token value is provided (just Enter is hit) then this new machine will be waiting for authorization. To
        see unauthorized machines select the <b>Unauthorized</b> button at the top right.
    </p>

    <button
        type="button"
        pButton
        icon="pi pi-times"
        label="Close"
        (click)="closeAgentInstallationInstruction()"
        style="float: right"
        id="close-agent-installation-instruction-button"
    ></button>
</p-dialog>

<p-tabMenu [model]="tabs" [activeItem]="activeItem" styleClass="mb-2" [scrollable]="true">
    <ng-template pTemplate="item" let-item let-i="index">
        <a role="menuitem" pRipple [routerLink]="item.routerLink" class="p-ripple p-element p-menuitem-link">
            <div class="flex justify-content-between">
                <div class="p-menuitem-icon" [ngClass]="item.icon" *ngIf="item.icon"></div>
                <div class="p-menuitem-text">
                    <b>{{ item.label }}</b>
                </div>
                <div
                    class="pi pi-times close-tab-btn"
                    (click)="closeTab($event, i)"
                    id="{{ 'close-machine-tab-' + item.label }}"
                    *ngIf="i !== 0"
                ></div>
            </div>
        </a>
    </ng-template>
</p-tabMenu>

<!-- Machines tab -->
<div *ngIf="activeTabIdx === 0">
    <div class="flex flex-wrap gap-2 justify-content-end mb-3">
        <span class="p-input-icon-left flex min-w-0">
            <i class="pi pi-search"></i>
            <input
                type="text"
                id="filter-machines-text-field"
                pInputText
                placeholder="Search machines"
                (input)="inputFilterText(machinesTable, $event.target?.value)"
                (keyup.enter)="inputFilterText(machinesTable, $event.target?.value, true)"
                [value]="machinesTable.filters?.text?.value || machinesTable.filters?.text?.[0]?.value"
                class="min-w-0"
                #searchInput
            />
            <app-help-tip subject="filtering" id="filtering-help-button" [target]="searchInput">
                <p>
                    Machines in the table below can be filtered by entering a text in the search box; the table shows
                    all machines matching the filter text. Currently supported fields for such filtering are:
                </p>
                <ul>
                    <li>Address</li>
                    <li>Agent Version</li>
                    <li>Hostname</li>
                    <li>OS</li>
                    <li>Platform</li>
                    <li>Platform Family</li>
                    <li>Platform Version</li>
                    <li>Kernel Version</li>
                    <li>Kernel Arch</li>
                    <li>Virtualization System</li>
                    <li>Virtualization Role</li>
                    <li>Host ID</li>
                </ul>
                <p>
                    The search is performed while typing or on pressing Enter. The minimum number of search characters
                    is 3.
                </p>
            </app-help-tip>
        </span>
        <button
            pButton
            label="Clear"
            class="ml-2 flex-none"
            icon="pi pi-filter-slash"
            (click)="clearFilters(machinesTable)"
        ></button>
        <div class="flex flex-auto gap-2 flex-wrap justify-content-end">
            <div class="flex-auto"></div>
            <button
                *ngIf="showUnauthorized && selectedMachines?.length > 0"
                type="button"
                pButton
                label="Authorize selected"
                id="authorize-selected-button"
                icon="pi pi-lock"
                (click)="authorizeSelectedMachines(machinesTable)"
            ></button>
            <button
                type="button"
                pButton
                label="Refresh"
                id="refresh-all-button"
                icon="pi pi-refresh"
                (click)="refreshMachinesList(machinesTable)"
            ></button>
            <button
                type="button"
                pButton
                label="How to Install Agent on New Machine"
                icon="pi pi-download"
                (click)="showAgentInstallationInstruction()"
                id="show-agent-installation-instruction-button"
            ></button>

            <p-selectButton
                [options]="viewSelectionOptions"
                [(ngModel)]="showUnauthorized"
                (onChange)="onSelectMachinesListChange(machinesTable)"
                [allowEmpty]="false"
                id="unauthorized-select-button"
            ></p-selectButton>
        </div>
    </div>

    <p-messages *ngIf="showUnauthorized && registrationDisabled" severity="warn">
        <ng-template pTemplate>
            <span class="pi pi-exclamation-triangle"></span>
            <div class="ml-2">
                Registration of the new machines is disabled. Navigate to the
                <a routerLink="/settings" class="font-semibold">Settings</a>
                page to enable the registration if you expect new machines on the list below.
            </div>
        </ng-template>
    </p-messages>

    <p-menu #machineMenu [popup]="true" [model]="machineMenuItems"></p-menu>
    <p-table
        #machinesTable
        [value]="machines"
        [paginator]="true"
        [rows]="10"
        [lazy]="true"
        (onLazyLoad)="loadMachines($event)"
        [totalRecords]="totalMachines"
        [rowsPerPageOptions]="[10, 30, 50]"
        [showCurrentPageReport]="true"
        [selectionPageOnly]="true"
        [(selection)]="selectedMachines"
        [loading]="dataLoading"
        (onStateRestore)="stateRestored($event)"
        dataKey="id"
        stateStorage="session"
        [stateKey]="stateKey"
        currentPageReportTemplate="{currentPage} of {totalPages} pages"
        styleClass="p-datatable-striped"
    >
        <ng-template pTemplate="emptymessage" let-columns>
            <tr>
                <td [attr.colspan]="showUnauthorized ? 5 : 13" style="padding: 20px 20px 20px 20px; font-size: 1.1em">
                    <i class="pi pi-info-circle text-2xl text-primary vertical-align-middle font-bold"></i>
                    No {{ showUnauthorized ? 'unauthorized' : 'authorized' }} machines found.
                    <span *ngIf="machinesTable.hasFilter()">
                        Try to clear filtering.
                        <button
                            pButton
                            label="Clear"
                            class="p-button-outlined"
                            icon="pi pi-filter-slash"
                            (click)="clearFilters(machinesTable)"
                        ></button>
                    </span>
                    <div style="margin-top: 15px">
                        <i class="pi pi-info-circle text-xl text-primary-600 vertical-align-middle"></i>
                        Information about adding new machines to Stork server is available after clicking on the
                        <b>How to Install Agent to New Machine</b> button at the top.
                    </div>
                    <div *ngIf="!showUnauthorized && unauthorizedMachinesCount > 0">
                        <i class="pi pi-info-circle text-xl text-primary-600 vertical-align-middle"></i>
                        There {{ unauthorizedMachinesCount === 1 ? 'is' : 'are' }}
                        <b class="text-xl text-red-500">{{ unauthorizedMachinesCount }}</b>
                        unauthorized machine{{ unauthorizedMachinesCount > 1 ? 's' : '' }}. Check
                        {{ unauthorizedMachinesCount === 1 ? 'it' : 'them' }} by selecting <b>Unauthorized</b> button
                        above.
                    </div>
                    <div *ngIf="showUnauthorized">
                        <i class="pi pi-info-circle text-xl text-primary-600 vertical-align-middle"></i>
                        There are no machines waiting for the authorization. You can now select the <b>Authorized</b>
                        button above to see all authorized machines.
                    </div>
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="header">
            <tr *ngIf="!showUnauthorized">
                <th style="width: 8rem">Hostname</th>
                <th style="width: 10rem">
                    Location
                    <app-help-tip subject="Location" id="location-help-button">
                        <p>
                            Specifies where the server can reach the agent as a hostname:tcp-port pair (e.g.
                            localhost:8888).
                        </p></app-help-tip
                    >
                </th>
                <th style="width: 4.5rem">Agent Version</th>
                <th class="w-4rem">App(s) Version</th>
                <th style="width: 7rem">Daemons</th>
                <th style="width: 4rem">CPUs</th>
                <th style="width: 8rem">
                    CPU Load
                    <app-help-tip subject="CPU Load" id="cpu-load-help-button">
                        <p>
                            These three numbers are CPU load averages for last 1 minute, 5 minutes and 15 minutes. This
                            is the usual syntax used by <b>top</b> command.
                        </p>

                        <p>
                            High load averages imply that a system is overloaded. A value of 1.00 means one CPU core is
                            fully utilized. For example, if your system has load of 1.22 and you have only 1 CPU core,
                            the system is overloaded. However, if there are 4 cores, you system is working at a bit over
                            30% of its capacity.
                        </p>
                    </app-help-tip>
                </th>
                <th style="width: 5rem">Total Memory [GB]</th>
                <th style="width: 7rem">Memory Usage [%]</th>
                <th class="hiding-column" style="width: 6rem">Uptime</th>
                <th class="hiding-column" style="width: 6rem">
                    Last Refreshed
                    <app-help-tip subject="Last refreshed" id="last-refreshed-help-button"
                        ><p>
                            When the machine status was last retrieved. You can refresh it by clicking Refresh in the
                            Action menu.
                        </p></app-help-tip
                    >
                </th>
                <th style="width: 13rem">Error</th>
                <th style="width: 4rem">Action</th>
            </tr>
            <tr *ngIf="showUnauthorized">
                <th style="width: 4rem">
                    <p-tableHeaderCheckbox></p-tableHeaderCheckbox>
                </th>
                <th style="width: 8rem">Hostname</th>
                <th style="width: 10rem">
                    Location
                    <app-help-tip subject="Location" id="location-2-help-button">
                        <p>
                            Specifies a host name and the TCP port where the server can reach the agent, e.g.
                            localhost:8888).
                        </p></app-help-tip
                    >
                </th>
                <th>
                    Agent Token
                    <app-help-tip subject="Agent Token" id="agent-token-help-button">
                        <p>
                            This is a token generated by an agent during its first start up. Verify if value visible
                            here is the same as agent token present in its logs or in
                            <span style="font-family: monospace">/var/lib/stork-agent/tokens/agent-token.txt</span>.
                        </p>
                    </app-help-tip>
                </th>
                <th style="width: 4rem">Action</th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-m>
            <tr *ngIf="!showUnauthorized">
                <td>
                    <a routerLink="/machines/{{ m.id }}">{{ m.hostname || m.address }}</a>
                </td>
                <td>{{ m.address }}:{{ m.agentPort }}</td>
                <td>
                    {{ m.agentVersion }}
                    <app-version-status app="stork" [version]="m.agentVersion"></app-version-status>
                </td>
                <td>
                    <ng-container *ngFor="let a of m.apps"
                        ><app-version-status
                            [app]="a.type"
                            [version]="a.version"
                            [showAppName]="true"
                        ></app-version-status
                    ></ng-container>
                </td>
                <td>
                    <div *ngFor="let a of m.apps">
                        <app-app-daemons-status [app]="a"></app-app-daemons-status>
                    </div>
                </td>
                <td>{{ m.cpus }}</td>
                <td>{{ m.cpusLoad }}</td>
                <td>{{ m.memory }}</td>
                <td><p-progressBar [value]="m.usedMemory"></p-progressBar></td>
                <td class="hiding-column">{{ m.uptime || '?' }} days</td>
                <td class="hiding-column">{{ m.lastVisitedAt | localtime | placeholder: 'never' }}</td>
                <td>
                    <p-message *ngIf="m.error" severity="error" text="{{ m.error }}"></p-message>
                </td>
                <td>
                    <button
                        type="button"
                        pButton
                        icon="pi pi-bars"
                        id="show-machines-menu"
                        (click)="showMachineMenu($event, machineMenu, m, machinesTable)"
                    ></button>
                </td>
            </tr>
            <tr *ngIf="showUnauthorized">
                <td>
                    <p-tableCheckbox [value]="m"></p-tableCheckbox>
                </td>
                <td>
                    <a routerLink="/machines/{{ m.id }}">{{ m.hostname || m.address }}</a>
                </td>
                <td>{{ m.address }}:{{ m.agentPort }}</td>
                <td>{{ m.agentToken }}</td>
                <td>
                    <button
                        type="button"
                        pButton
                        icon="pi pi-bars"
                        id="show-machines-menu"
                        (click)="showMachineMenu($event, machineMenu, m, machinesTable)"
                    ></button>
                </td>
            </tr>
        </ng-template>
        <ng-template pTemplate="paginatorright" let-state>
            Total: {{ state.totalRecords > 0 ? state.totalRecords : '0' }}
            {{ state.totalRecords === 1 ? 'machine' : 'machines' }}
        </ng-template>
    </p-table>
</div>

<!-- Single machine tab -->
<div *ngIf="activeTabIdx !== 0" class="p-component">
    <div class="grid" style="width: 100%">
        <div class="col-12 flex gap-3 column-gap-8 row-gap-3 flex-wrap">
            <div class="text-2xl font-bold text-primary-600 ml-2 mt-2">
                <i class="fa fa-server pr-2"></i> {{ machineTab.machine.address
                }}<span class="text-primary-200">:{{ machineTab.machine.agentPort }}</span>
                <i
                    class="pi pi-pencil vertical-align-text-top ml-1 text-gray-400 cursor-pointer"
                    id="edit-machine-icon"
                    (click)="editAddress(machineTab)"
                ></i>
            </div>

            <div>
                <p-message
                    *ngIf="machineTab.machine.error"
                    severity="error"
                    text="{{ machineTab.machine.error }}"
                ></p-message>
            </div>
        </div>

        <div class="col-12 xl:col-7 grid">
            <div class="col-12 md:col-6">
                <h3>System Information</h3>
                <table [class.text-color-secondary]="machineTab.machine.error">
                    <tr>
                        <td>Address</td>
                        <td>{{ machineTab.machine.address }}:{{ machineTab.machine.agentPort }}</td>
                    </tr>
                    <tr>
                        <td>Hostname</td>
                        <td>{{ machineTab.machine.hostname }}</td>
                    </tr>
                    <tr>
                        <td>Agent Version</td>
                        <td>
                            {{ machineTab.machine.agentVersion }}
                            <app-version-status
                                *ngIf="machineTab.machine.authorized"
                                app="stork"
                                [version]="machineTab.machine.agentVersion"
                            ></app-version-status>
                        </td>
                    </tr>
                    <tr>
                        <td>CPUs</td>
                        <td>{{ machineTab.machine.cpus }}</td>
                    </tr>
                    <tr>
                        <td class="flex align-items-center justify-content-between">
                            <span>CPUs Load</span>
                            <app-help-tip subject="CPU Load" id="cpu-load-2-help-button">
                                <p>
                                    These three numbers are CPU load averages for last 1 minute, 5 minutes and 15
                                    minutes. This is the usual syntax used by <b>top</b> command.
                                </p>

                                <p>
                                    High load averages imply that a system is overloaded. A value of 1.00 means one CPU
                                    core is fully utilized. For example, if your system has load of 1.22 and you have
                                    only 1 CPU core, the system is overloaded. However, if there are 4 cores, you system
                                    is working at a bit over 30% of its capacity.
                                </p>
                            </app-help-tip>
                        </td>
                        <td>{{ machineTab.machine.cpusLoad }}</td>
                    </tr>
                    <tr>
                        <td>Memory</td>
                        <td>{{ machineTab.machine.memory || '?' }} GiB</td>
                    </tr>
                    <tr>
                        <td>Used Memory</td>
                        <td>{{ machineTab.machine.usedMemory }} %</td>
                    </tr>
                    <tr>
                        <td>Uptime</td>
                        <td>{{ machineTab.machine.uptime || '?' }} days</td>
                    </tr>
                    <tr>
                        <td>OS</td>
                        <td>{{ machineTab.machine.os }}</td>
                    </tr>
                    <tr>
                        <td>Platform Family</td>
                        <td>{{ machineTab.machine.platformFamily }}</td>
                    </tr>
                    <tr>
                        <td>Platform</td>
                        <td>{{ machineTab.machine.platform }}</td>
                    </tr>
                    <tr>
                        <td>Platform Version</td>
                        <td>{{ machineTab.machine.platformVersion }}</td>
                    </tr>
                    <tr>
                        <td>Kernel Version</td>
                        <td>{{ machineTab.machine.kernelVersion }}</td>
                    </tr>
                    <tr>
                        <td>Kernel Arch</td>
                        <td>{{ machineTab.machine.kernelArch }}</td>
                    </tr>
                    <tr>
                        <td>Virtualization Role</td>
                        <td>{{ machineTab.machine.virtualizationRole }}</td>
                    </tr>
                    <tr *ngIf="machineTab.machine.virtualizationRole === 'guest'">
                        <td>Virtualization System</td>
                        <td>{{ machineTab.machine.virtualizationSystem }}</td>
                    </tr>
                    <tr>
                        <td class="flex align-items-center justify-content-between">
                            <span>Use HTTP credentials</span>
                            <app-help-tip subject="Use HTTP credentials">
                                <p>
                                    Indicates if the Stork Agent includes the HTTP credentials (i.e., Basic Auth user
                                    and password) in the requests sent to the Kea Control Agent.
                                </p>
                                <p>
                                    The credentials are included only in the requests to the hosts specified in the
                                    configuration file. Other hosts don't receive any authorization data.
                                </p>
                            </app-help-tip>
                        </td>
                        <td>
                            {{ !!machineTab.machine.agentUsesHttpCredentials }}
                            <i class="pi pi-key" *ngIf="machineTab.machine.agentUsesHttpCredentials"></i>
                        </td>
                        <td></td>
                    </tr>
                    <tr>
                        <td>Host ID</td>
                        <td>{{ machineTab.machine.hostID }}</td>
                    </tr>
                    <tr>
                        <td>Last Visited</td>
                        <td>{{ machineTab.machine.lastVisitedAt | localtime | placeholder: 'never' }}</td>
                    </tr>
                </table>

                <button
                    *ngIf="machineTab.machine.authorized"
                    type="button"
                    pButton
                    label="Get Latest State"
                    id="get-latest-state-button"
                    icon="pi pi-refresh"
                    class="mt-3 mr-2 mb-2"
                    (click)="refreshMachineState(machineTab)"
                ></button>
                <button
                    *ngIf="machineTab.machine.authorized"
                    type="button"
                    pButton
                    label="Dump Troubleshooting Data"
                    id="dump-single-machine"
                    icon="pi pi-download"
                    title="Download data archive for troubleshooting purposes"
                    class="mt-3 mr-2 mb-2 p-button-secondary"
                    (click)="downloadDump(machineTab.machine)"
                ></button>
            </div>
            <div class="col-12 md:col-6">
                <h3>Applications</h3>
                <div *ngFor="let app of machineTab.machine.apps">
                    <h4 *ngIf="app.type === 'kea'">Kea App ({{ app.name }})</h4>
                    <h4 *ngIf="app.type === 'bind9'">BIND 9 App</h4>
                    <a routerLink="/apps/{{ app.type }}/{{ app.id }}">Version {{ app.version }}</a>
                    <app-version-status [app]="app.type" [version]="app.version"></app-version-status>
                    <br />
                    <app-app-daemons-status [app]="app"></app-app-daemons-status>
                </div>
            </div>
        </div>
        <div class="col-12 xl:col-5">
            <h3>Events</h3>
            <app-events-panel #eventsTable [filter]="{ machine: machineTab.machine.id }"></app-events-panel>
        </div>
    </div>
</div>
