import {
  ConfigurablePinArray,
  DAC,
  GPS,
  I2C,
  I2CWithChannels,
  Incremental,
  Invalid,
  Modem,
  Power
} from "pbHelpers/AddressTypes";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { SPI } from "./AddressTypes/SPI";

export interface AddressTypeExtension {
  addressType: quack.AddressType;
  friendlyName: string;
  humanReadableAddress: (
    componentType: quack.ComponentType,
    address: number,
    product?: pond.DeviceProduct
  ) => string;
  singular: boolean;
}

const ADDRESS_TYPE_MAP = new Map<quack.AddressType, AddressTypeExtension>([
  [quack.AddressType.ADDRESS_TYPE_INVALID, Invalid],
  [quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY, ConfigurablePinArray],
  [quack.AddressType.ADDRESS_TYPE_I2C, I2C],
  [quack.AddressType.ADDRESS_TYPE_DAC, DAC],
  [quack.AddressType.ADDRESS_TYPE_POWER, Power],
  [quack.AddressType.ADDRESS_TYPE_GPS, GPS],
  [quack.AddressType.ADDRESS_TYPE_MODEM, Modem],
  [quack.AddressType.ADDRESS_TYPE_I2C_WITH_CHANNELS, I2CWithChannels],
  [quack.AddressType.ADDRESS_TYPE_INCREMENTAL, Incremental],
  [quack.AddressType.ADDRESS_TYPE_SPI, SPI]
]);

export function getAddressTypeExtension(addressType: quack.AddressType): AddressTypeExtension {
  const addressTypes = Array.from(ADDRESS_TYPE_MAP.keys());
  //cable offsets (id) are still technically the configurable pin array
  if (
    addressType >= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET1 &&
    addressType <= quack.AddressType.ADDRESS_TYPE_PIN_OFFSET100
  ) {
    addressType = quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY;
  }
  for (var i = 0; i < addressTypes.length; i++) {
    let key = addressTypes[i];
    if (addressType === key) {
      return ADDRESS_TYPE_MAP.get(key) as AddressTypeExtension;
    }
  }
  return Invalid;
}

export function getFriendlyAddressTypeName(addressType: quack.AddressType): string {
  return getAddressTypeExtension(addressType).friendlyName;
}

export function getHumanReadableAddress(
  addressType: quack.AddressType,
  componentType: quack.ComponentType,
  address: number,
  product?: pond.DeviceProduct
): string {
  return getAddressTypeExtension(addressType).humanReadableAddress(componentType, address, product);
}

export function isSingular(
  addressType: quack.AddressType,
  componentType: quack.ComponentType
): boolean {
  if (addressType === quack.AddressType.ADDRESS_TYPE_I2C) {
    switch (componentType) {
      case quack.ComponentType.COMPONENT_TYPE_PRESSURE:
        return false;
      case quack.ComponentType.COMPONENT_TYPE_LIGHT:
        return true;
      case quack.ComponentType.COMPONENT_TYPE_CO2:
        return true;
      case quack.ComponentType.COMPONENT_TYPE_STEPPER_MOTOR:
        return false;
      default:
        return false;
    }
  }

  return getAddressTypeExtension(addressType).singular;
}
