import {
  Actions,
  ActionType,
} from './discover.action';

import {
  State,
  initialState,
} from './discover.state';

import {
  Zone,
  Host,
  Port,
  Service,
} from '@overflow/commons-typescript/model/discovery';

// import * as _ 'lodash';

export function reducer(state = initialState, action: Actions): State {
  switch (action.type) {
    case ActionType.DiscoveryStart: {

      return {
        ...state,
        isStart: true
      };
    }
    case ActionType.DiscoveryStop: {
      return {
        ...state,
        isEnd: true
      };
    }
    case ActionType.DiscoveredZone: {
      const zone: Zone = <Zone>action.payload;
      const zones: Map<string, Zone> = null === state.zones ? new Map() : state.zones;

      zones.set(zone.network, zone);

      const newZones: Map<string, Zone> = new Map();

      zones.forEach(function(value, key) {
        newZones.set(key, value);
      });

      return {
        ...state,
        zones : newZones,
      };
    }

    case ActionType.DiscoveredHost: {
      const host: Host = <Host>action.payload;
      let zone = null;

      let zones: Map<string, Zone> = state.zones;

      if (zones === undefined || zones === null) {
        zones = new Map();
        zone = host.zone;
        // zones.set(zone.network, zone);
      } else {
        zone = zones.get(host.zone.network);
      }

      if (undefined === zone) {
        // console.error(`Discovery.discoveredHost: Zone[${host.zone.network}] is not exist`);
        zone = new Map();
      }
      if (null === zone.hosts || undefined === zone.hosts) {
        zone.hosts = new Map();
        zone.hosts.set(host.ipv4, host);
      } else {
        if (zone.hosts.has(host.ipv4) === false) {
          zone.hosts.set(host.ipv4, host);
        }
      }

      zones.set(zone.network, zone);

      const newZones: Map<string, Zone> = new Map();

      zones.forEach(function(value, key) {
        newZones.set(key, value);
      });

      return {
        ...state,
        zones: newZones
      };
    }

    case ActionType.DiscoveredPort: {
      const port: Port = <Port>action.payload;
      let zone = state.zones.get(port.host.zone.network);

      let zones: Map<string, Zone> = state.zones;

      if (zones === undefined || zones === null) {
        zones = new Map();
      }

      if (zone === undefined || zone === null) {
        zone = port.host.zone;
      }

      // if (undefined === zone) {
      //   console.error(`Discovery.DiscoveredPort: Zone[${port.host.zone.network}] is not exist`);
      // }

      // if (null === zone.hosts || undefined === zone.hosts.get(port.host.ip)) {
      //   console.error(`Discovery.DiscoveredPort: Host[${port.host.ip}] is not exist`);
      //   return state;
      // }

      if (zone.hosts === undefined || zone.hosts === null) {
          zone.hosts = new Map();
      }
      let host: Host = null;
      host = zone.hosts.get(port.host.ipv4);

      if (host === undefined || host === null) {
        host = port.host;
      }

      if (null === host.ports || undefined === host.ports) {
        host.ports = new Map();
        host.ports.set(port.portNumber, port);
      } else {
        if (host.ports.has(port.portNumber) === false) {
          host.ports.set(port.portNumber, port);
        }
      }

      zone.hosts.set(host.ipv4, host);
      zones.set(zone.network, zone);

      const newZones: Map<string, Zone> = new Map();

      zones.forEach(function(value, key) {
        newZones.set(key, value);
      });

      return {
        ...state,
        zones: newZones
      };

    }

    case ActionType.DiscoveredService: {
      const service: Service = <Service>action.payload;
      let zone = state.zones.get(service.port.host.zone.network);

      let zones: Map<string, Zone> = state.zones;

      if (zones === undefined || zones === null) {
        zones = new Map();
      }

      if (zone === undefined || zone === null) {
        zone = service.port.host.zone;
      }

      if (zone.hosts === undefined || zone.hosts === null) {
        zone.hosts = new Map();
      }

      // if (undefined === zone) {
      //   console.error(`Discovery.DiscoveredService: Zone[${service.port.host.zone.network}] is not exist`);
      // }
      // if (null === zone.hosts || undefined === zone.hosts.get(service.port.host.ip)) {
      //   console.error(`Discovery.DiscoveredPort: Host[${service.port.host.ip}] is not exist`);
      // }
      let host: Host = null;
      host = zone.hosts.get(service.port.host.ipv4);

      if (host === undefined || host === null) {
        zone.hosts.set(service.port.host.ipv4, service.port.host);
        host = service.port.host;
      }

      if (undefined === host.ports || null === host.ports) {
        host.ports = new Map();
        host.ports.set(service.port.portNumber, service.port);
      }

      let port: Port = null;
      port = host.ports.get(service.port.portNumber);

      if (undefined === port || null === port) {
        port = service.port;
      }

      if ( undefined === port.services || null === port.services) {
        port.services = new Map();
      }
      port.services.set(service.serviceName, service);

      host.ports.set(service.port.portNumber, port);
      zone.hosts.set(host.ipv4, host);
      zones.set(zone.network, zone);

      const newZones: Map<string, Zone> = new Map();

      zones.forEach(function(value, key) {
        newZones.set(key, value);
      });

      return {
        ...state,
        zones: newZones
      };
    }

    default: {
      return state;
    }
  }
}


// function checkZone(state, pZone: Zone) :  {


// }