/*
 * Copyright (c) [2020] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact SUSE LLC.
 *
 * To contact SUSE LLC about this file by physical or electronic mail, you may
 * find current contact information at www.suse.com.
 */

import cockpit from "cockpit";
import React, { useState, useEffect, useCallback } from 'react';
import {
    Table,
    TableBody,
    TableHeader,
    TableVariant,
    cellWidth,
    expandable,
    truncate
} from '@patternfly/react-table';
import { Spinner } from '@patternfly/react-core';
import AlertIcon from '@patternfly/react-icons/dist/js/icons/exclamation-triangle-icon';
import InterfaceDetails from "./InterfaceDetails";
import interfaceType from '../lib/model/interfaceType';
import interfaceStatus from '../lib/model/interfaceStatus';
import { createConnection } from '../lib/model/connections';

const _ = cockpit.gettext;

const InterfacesList = ({ interfaces = [], connections = [] }) => {
    const [rows, setRows] = useState([]);
    const [openRows, setOpenRows] = useState([]);

    const columns = [
        { title: "", props: { className: "status-column" } },
        { title: _("Name"), cellFormatters: [expandable] },
        { title: _("Type") },
        { title: _("Status"), transforms: [cellWidth(10)], cellTransforms: [truncate] },
        { title: _("Addresses") }
    ];

    const interfaceAddresses = (iface) => {
        if (iface.addresses.length === 0) return;

        return iface.addresses.map(i => i.local).join(', ');
    };

    const renderStatusIcon = (iface) => {
        if (!iface.status) return;

        if (iface.error) {
            return <><AlertIcon /></>;
        } else if (iface.status !== interfaceStatus.READY) {
            return <><Spinner size="md" /></>;
        }
    };

    const renderStatusText = (iface) => {
        const linkText = iface.link ? _('Up') : _('Down');

        if (!iface.status || iface.status === interfaceStatus.READY) {
            return linkText;
        } else {
            return interfaceStatus.label(iface.status);
        }
    };

    /**
     * Returns the connection for given interface name or a fake one if it does not exist yet
     *
     * When a connection does not exist yet, the user should be able to create one by configuring
     * the interface. To achieve that, a "default" connection object is needed, in order to build
     * the needed UI.
     *
     * @param {string} name - the interface/connection name
     * @return {module:model/connections~Connection}
     */
    const findOrCreateConnection = useCallback((name) => {
        return connections.find(c => c.name === name) || createConnection({ name, exists: false });
    }, [connections]);

    /**
     * Builds the needed structure for rendering the interfaces and their details in an expandable
     * Patternfly/Table
     */
    const buildRows = useCallback(() => {
        let parentId = 0;

        return interfaces.reduce((list, i) => {
            const conn = findOrCreateConnection(i.name);

            list.push(
                {
                    isOpen: openRows.includes(parentId),
                    cells: [
                        renderStatusIcon(i),
                        i.name,
                        interfaceType.label(i.type),
                        renderStatusText(i),
                        interfaceAddresses(i)
                    ]
                }
            );
            list.push(
                {
                    parent: parentId,
                    cells: [
                        "",
                        {
                            title: <InterfaceDetails iface={i} connection={conn} />,
                            props: { colSpan: 4 }
                        }
                    ]
                }
            );

            parentId += 2;

            return list;
        }, []);
    }, [interfaces, openRows, findOrCreateConnection]);

    /**
     * Keeps the openRows internal state up to date using the information provided by the
     * Patternfly/Table#onCollapse event
     */
    const onCollapseFn = () => (event, rowKey, isOpen) => {
        if (isOpen && !openRows.includes(rowKey)) {
            setOpenRows([...openRows, rowKey]);
        } else {
            setOpenRows(openRows.filter(k => k != rowKey));
        }
    };

    useEffect(() => {
        setRows(buildRows());
    }, [buildRows]);

    return (
        <Table
            aria-label="Networking interfaces"
            variant={TableVariant.compact}
            onCollapse={onCollapseFn()}
            className="interfaces-list"
            cells={columns}
            rows={rows}
        >
            <TableHeader />
            <TableBody />
        </Table>
    );
};

export default InterfacesList;