/**
 * @author Martin Karkowski
 * @email m.karkowski@zema.de
 * @create date 2020-12-03 11:57:29
 * @modify date 2020-12-03 11:57:29
 * @desc [description]
 */

import React from "react";
import { Card, Col, ProgressBar, Row, Table } from "react-bootstrap";
import {
  IDispatcherInfo,
  INopeDispatcher
} from "../../lib/types/nope/nopeDispatcher.interface";
import { INopeObserver } from "../../lib/types/nope/nopeObservable.interface";

/**
 * Component used to render the Status of the Memory of a Host.
 */
class MemoryStatusComponent extends React.Component<
  {
    value: number;
  },
  {}
> {
  render() {
    // Determine the Now Value.
    const now = Math.round(1000 - this.props.value * 1000) / 10;
    const colorRange = {
      "0": "success",
      "30": "success",
      "75": "warning",
      "90": "danger",
      "101": "danger"
    };

    // Determine the Color, Therefore filter the "keys" based on the now Value.
    const color =
      colorRange[
        Object.getOwnPropertyNames(colorRange).filter(
          (value) => now < parseFloat(value)
        )[0]
      ];

    // Render
    return (
      <>
        <ProgressBar now={now} label={`${now} %`} variant={color} />
      </>
    );
  }
}

class HostStatusComponent extends React.Component<
  {
    status: {
      cores: number;
      cpu: string;
      os: string;
      ram: number;
      name: string;
      pids: { pid: number; dispatchers: string[] }[];
    };
  },
  {}
> {
  render() {
    return (
      <Card>
        <Card.Body>
          <Card.Title>{this.props.status.name}</Card.Title>
          <Table bordered>
            <tbody>
              <tr>
                <td>RAM</td>
                <td>
                  {" "}
                  {/* Rendert the Memory */}
                  <MemoryStatusComponent
                    value={this.props.status.ram}
                  ></MemoryStatusComponent>
                </td>
              </tr>
              <tr>
                <td>CPU</td>
                <td>{this.props.status.cpu}</td>
              </tr>
              <tr>
                <td>Cores</td>
                <td>{this.props.status.cores}</td>
              </tr>
              <tr>
                <td>Nope-Processes</td>
                <td>{this.props.status.pids.length}</td>
              </tr>
            </tbody>
          </Table>
        </Card.Body>
        <Card.Footer>
          <small className="text-muted">Last updated 3 mins ago</small>
        </Card.Footer>
      </Card>
    );
  }
}

class AvailableDispatchers extends React.Component<
  { dispatcher: INopeDispatcher },
  { dispatchers: IDispatcherInfo[][]; connected: boolean }
> {
  private _observer: INopeObserver[] = [];

  private __sort() {
    const sorted: {
      [index: string]: {
        cpu: string;
        cores: number;
        os: string;
        ram: number;
        name: string;
        pids: { [index: string]: string[] };
      };
    } = {};
    const ret: {
      cpu: string;
      cores: number;
      os: string;
      ram: number;
      name: string;
      pids: { pid: number; dispatchers: string[] };
    }[] = [];

    for (const dispatcher of this.props.dispatcher.externalDispatchers.getContent()) {
      if (sorted[dispatcher.host.name] === undefined) {
        sorted[dispatcher.host.name] = {
          cores: dispatcher.host.cores,
          cpu: dispatcher.host.cpu,
          name: dispatcher.host.name,
          os: dispatcher.host.os,
          pids: {},
          ram: dispatcher.host.ram
        };
      }
      if (sorted[dispatcher.host.name].pids[dispatcher.pid] === undefined) {
        console.log(dispatcher.pid);
        sorted[dispatcher.host.name].pids[dispatcher.pid] = [];
      }

      sorted[dispatcher.host.name].pids[dispatcher.pid].push(dispatcher.id);
    }

    for (const hostname in sorted) {
      const _toAdd: any = sorted[hostname];
      _toAdd.pids = Object.getOwnPropertyNames(sorted[hostname].pids).map(
        (pid) => {
          return {
            pid,
            dispatchers: sorted[hostname].pids[pid]
          };
        }
      );

      ret.push(_toAdd);
    }

    return ret;
  }

  private __refresh__() {
    const connected = this.props.dispatcher.communicator.connected.getContent();
    const dispatchers = [];
    const maxItems = 3;
    const sorted = [
      ...this.__sort(),
      ...this.__sort(),
      ...this.__sort(),
      ...this.__sort()
    ];

    // Function to Split the Dispatcher Array into an array containing max 3 elements.
    for (let i = 0; i < sorted.length; i = i + maxItems) {
      dispatchers.push(sorted.slice(i, i + maxItems));
    }

    this.setState({
      dispatchers: connected ? dispatchers : [],
      connected
    });
  }

  /**
   * Function will be called if the Item has been rendered sucessfully.
   */
  componentDidMount() {
    if (this.props.dispatcher) {
      // Subscribe to the Instances.
      const _this = this;

      this._observer.push(
        this.props.dispatcher.externalDispatchers.subscribe(() => {
          _this.__refresh__();
        })
      );

      this._observer.push(
        this.props.dispatcher.communicator.connected.subscribe(() => {
          _this.__refresh__();
        })
      );

      // Render the Elements
      this.__refresh__();
    }
  }

  /**
   * Function, that will be called before the network fails.
   */
  componentWillUnmount() {
    // Call the unmount
    for (const _observer of this._observer) {
      _observer.unsubscribe();
    }
  }

  constructor(props) {
    super(props);
    this.state = {
      dispatchers: [],
      connected: false
    };
  }

  public render() {
    return (
      <>
        {this.state.dispatchers.map((row, idx_01) => {
          return (
            <Row
              key={idx_01}
              style={{ paddingTop: "0.5rem", paddingBottom: "0.5rem" }}
            >
              {row.map((item, idx_02) => {
                return (
                  <Col key={`${idx_01}_${idx_02}`} sm={4}>
                    <HostStatusComponent status={item}></HostStatusComponent>
                  </Col>
                );
              })}
            </Row>
          );
        })}
      </>
    );
  }
}

export default AvailableDispatchers;
