import {
  Box,
  Button,
  Checkbox,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Divider,
  FormControlLabel,
  Grid2 as Grid,
  IconButton,
  MenuItem,
  Step,
  StepLabel,
  Stepper,
  Switch,
  Tab,
  Tabs,
  TextField,
  Theme,
  Tooltip,
  Typography
} from "@mui/material";
import DeleteButton from "common/DeleteButton";
import ResponsiveDialog from "common/ResponsiveDialog";
import SearchSelect, { Option } from "common/SearchSelect";
import { useComponentAPI, useDeviceAPI, usePrevious, useSnackbar } from "hooks";
import { cloneDeep } from "lodash";
import { Component, Device } from "models";
import {
  getFriendlyAddressTypeName,
  getHumanReadableAddress,
  isSingular
} from "pbHelpers/AddressType";
import {
  extension,
  getAddressTypes,
  GetComponentTypeOptions,
  getFriendlyName,
  getMeasurements,
  isController
} from "pbHelpers/ComponentType";
import {
  ComponentAvailabilityMap,
  DeviceAvailabilityMap,
  OffsetAvailabilityMap
} from "pbHelpers/DeviceAvailability";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import React, { useCallback, useEffect, useState } from "react";
import { or } from "utils/types";
import { ConfigurablePin } from "pbHelpers/AddressTypes";
import ColourPicker from "common/ColourPicker";
import classNames from "classnames";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import ComponentForm from "./ComponentForm";
import { green, red } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import {
  Remove as RemoveIcon,
  Add as AddIcon,

} from "@mui/icons-material"
import CancelSubmit from "common/CancelSubmit";
import { useGlobalState } from "providers";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    stepper: {
      paddingRight: 0,
      paddingLeft: 0
    },
    switchControl: {
      marginLeft: theme.spacing(0.25),
      [theme.breakpoints.up("sm")]: {
        marginLeft: theme.spacing(1)
      }
    },
    selectInput: {
      minHeight: "48px"
    },
    fullWidth: {
      width: "100%"
    },
    heading: {
      fontSize: theme.typography.pxToRem(13),
      flexBasis: "25%",
      flexShrink: 0
    },
    secondaryHeading: {
      fontSize: theme.typography.pxToRem(13),
      color: theme.palette.text.secondary
    },
    greenButton: {
      color: green["600"]
    },
    redButton: {
      color: red["600"]
    },
    noPadding: {
      padding: 0
    },
    dataUsageCard: { width: "100%" },
    dataUsageHeader: { paddingBottom: 0 },
    dataUsageIcon: { color: "var(--status-warning)" },
    dataUsageContent: { paddingTop: 0 }
  })
});

interface Props {
  device: Device;
  component?: Component;
  isDialogOpen: boolean;
  closeDialogCallback: () => void;
  availablePositions: DeviceAvailabilityMap;
  availableOffsets: OffsetAvailabilityMap; //deprecated: this is no longer used with the change of cable id to be a number entry
  mode?: "add" | "remove" | "update";
  refreshCallback: () => void;
  canEdit: boolean;
  addressTypeRestriction?: quack.AddressType;
  deviceComponentPrefs?: pond.DeviceComponentPreferences;
}

interface TabPanelProps {
  children?: React.ReactNode;
  index: any;
  value: any;
}

function TabPanelMine(props: TabPanelProps) {
  const { children, value, index, ...other } = props;

  return (
    <div
      role="tabpanel"
      hidden={value !== index}
      aria-labelledby={`simple-tab-${index}`}
      {...other}>
      {value === index && <React.Fragment>{children}</React.Fragment>}
    </div>
  );
}

export default function ComponentSettings(props: Props) {
  const classes = useStyles();
  const componentAPI = useComponentAPI();
  const deviceAPI = useDeviceAPI();
  const { error, warning, success } = useSnackbar();
  const {
    device,
    isDialogOpen,
    closeDialogCallback,
    availablePositions,
    mode,
    refreshCallback,
    canEdit,
    addressTypeRestriction,
    deviceComponentPrefs
  } = props;
  const [{as}] = useGlobalState();
  const prevComponent = usePrevious(props.component);
  const prevIsDialogOpen = usePrevious(isDialogOpen);
  const steps = [0, 1];
  const [activeStep, setActiveStep] = useState(0);
  const [componentType, setComponentType] = useState<Option | null | undefined>();
  const componentTypeOptions: Option[] = GetComponentTypeOptions(addressTypeRestriction);
  const [removeDialogOpen, setRemoveDialogOpen] = useState(false);
  const [formComponent, setFormComponent] = useState<Component>(new Component());
  const [cableID, setCableID] = useState(0);
  const [expansionLine, setExpansionLine] = useState(0);
  const [overlayIndex, setOverlayIndex] = useState(0);
  const [overlayColourDialog, setOverlayCoulourDialog] = useState(false);
  const [tabVal, setTabVal] = useState(0);
  const [formValid, setFormValid] = useState(false);
  const [excludedNodes, setExcludedNodes] = useState<number[]>([]);
  const [nodeToExclude, setNodeToExclude] = useState(0);

  const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
    setTabVal(newValue);
  };

  // useEffect(() => {
  //   if (deviceComponentPrefs) {
  //     setExcludedNodes(deviceComponentPrefs.excludedNodes);
  //   }
  // }, [deviceComponentPrefs]);

  const init = useCallback(() => {
    let component = props.component;
    let initComponent = new Component();
    if (component) {
      initComponent.settings = cloneDeep(component.settings);
      initComponent.status = cloneDeep(component.status);
    }
    if (
      initComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE &&
      initComponent.settings.grainType === pond.Grain.GRAIN_INVALID
    ) {
      initComponent.settings.grainType = pond.Grain.GRAIN_NONE;
    }
    setComponentType(
      componentTypeOptions.find(
        t =>
          t.value ===
          initComponent.settings.type.toString() + ":" + initComponent.settings.subtype.toString()
      )
    );
    setFormComponent(initComponent);
    setExcludedNodes(initComponent.settings.excludedNodes)
  }, [props.component, componentTypeOptions]);

  useEffect(() => {
    if (props.component !== prevComponent || (!isDialogOpen && prevIsDialogOpen)) {
      init();
    }
  }, [props.component, prevComponent, init, isDialogOpen, prevIsDialogOpen]);

  const close = () => {
    closeDialogCallback();
  };

  const isFormValid = () => {
    //let { component } = form;
    let type = or(formComponent.settings.type, "");
    if(supportsExpansion() && expansionLine === 0){
      return false
    }
    return isComponentTypeValid(type) && isAddressValid(formComponent);
  };

  const isComponentTypeValid = (componentType: quack.ComponentType) => {
    if (!componentType) {
      return false;
    }

    return true;
  };

  const getAvailablePositions = (
    addressType: quack.AddressType,
    componentType: quack.ComponentType
  ): number[] => {
    let positions = availablePositions.get(addressType);
    if (!positions) return [];
    switch (addressType) {
      case quack.AddressType.ADDRESS_TYPE_I2C:
      case quack.AddressType.ADDRESS_TYPE_SPI:
        let componentPositions;
        if (positions) {
          componentPositions = (positions as ComponentAvailabilityMap).get(componentType);
        }
        return componentPositions ? (componentPositions as number[]) : [];
      case quack.AddressType.ADDRESS_TYPE_CONFIGURABLE_PIN_ARRAY:
        return positions ? (positions as ConfigurablePin[]).map(p => p.address) : [];
      default:
        return positions ? (positions as number[]) : [];
    }
  };

  const isAddressValid = (component: Component) => {
    let availablePosition = true;
    if (mode === "add") {
      let positions = getAvailablePositions(
        component.settings.addressType,
        component.settings.type
      );
      availablePosition = positions ? positions.length > 0 : false;
    }
    return (
      availablePosition &&
      (isSingular(component.settings.addressType, component.settings.type) ||
        or(component.settings.address, 0) >= 0)
    );
  };

  const hasAvailablePositions = (component: Component) => {
    // return true // TODO: actually fix this
    if (component.settings.addressType === quack.AddressType.ADDRESS_TYPE_INCREMENTAL) {
      return true;
    }
    const addressTypes: quack.AddressType[] = getAddressTypes(
      component.settings.type,
      component.settings.subtype
    );
    for (let i = 0; i < addressTypes.length; i++) {
      if (getAvailablePositions(addressTypes[i], component.settings.type).length > 0) {
        return true;
      }
    }
    return false;
  };

  const stepBack = () => {
    setActiveStep(activeStep - 1);
  };

  const stepNext = () => {
    setActiveStep(activeStep + 1);
  };

  const refresh = () => {
    if (refreshCallback) {
      refreshCallback();
    }
  };

  const addComponent = () => {
    const component = formComponent;
    //component.settings.calibrationCoefficient = Number(form.coefficient);
    if (cableID > 0) component.settings.addressType = cableID + 8;
    component.settings.expansionLine = expansionLine
    componentAPI
      .add(device.id(), component.settings, as)
      .then((_response: any) => {
        success(component.name() + " was successfully added!");
        refresh();
      })
      .catch((_err: any) => {
        error("Error occured while adding " + component.name() + ".");
      })
      .finally(() => close());
  };

  const updateComponent = () => {
    const component = formComponent;
    component.settings.excludedNodes = excludedNodes
    componentAPI
      .update(device.id(), component.settings, getContextKeys(), getContextTypes(), as)
      .then((_response: any) => {
        success(component.name() + " was successfully updated!");
        // let updatedPrefs = pond.DeviceComponentPreferences.create();
        // updatedPrefs.excludedNodes = excludedNodes;
        // deviceAPI
        //   .updateComponentPreferences(device.id(), component.key(), updatedPrefs, undefined, undefined, as)
        //   .then(_resp => {
        //     console.log("Preferences updated");
        //   })
        //   .catch(_err => {
        //     console.log("Preferences failed to update");
        //   });
        refresh();
      })
      .catch((_err: any) => {
        error("Error occured while updating " + component.name() + ".");
      })
      .finally(() => {
        close();
      });
  };

  const removeComponent = () => {
    componentAPI
      .remove(device.id(), formComponent.key(), getContextKeys(), getContextTypes(), as)
      .then((_response: any) => {
        success(formComponent.name() + " was successfully removed!");
        refresh();
      })
      .catch((err: any) => {
        err.response.data.error
          ? warning(err.response.data.error)
          : error("Error occured while removing " + formComponent.name() + ".");
      })
      .finally(() => {
        close();
      });
  };

  const handleTypeChanged = (option: Option | null) => {
    setComponentType(option);
    if (!option) {
      formComponent.settings = pond.ComponentSettings.create();
    } else {
      let rawType = option.value.split(":");
      let type = quack.ComponentType[rawType[0] as keyof typeof quack.ComponentType];
      let subtype = parseInt(rawType[1], 10);
      let ext = extension(type, subtype);
      formComponent.settings.type = type;
      formComponent.settings.subtype = subtype;
      formComponent.settings.addressType = or(addressTypeRestriction, getAddressTypes(
        formComponent.settings.type,
        formComponent.settings.subtype
      )[0]);
      formComponent.settings.address = or(
        getAvailablePositions(formComponent.settings.addressType, formComponent.settings.type)[0],
        Component.create().settings.address
      );
      formComponent.settings.name = option.label;
      if (type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
        formComponent.settings.grainType = pond.Grain.GRAIN_NONE;
      }
      let periodMs = Math.max(60000, ext.minMeasurementPeriodMs);
      formComponent.settings.measurementPeriodMs = periodMs;
      formComponent.settings.reportPeriodMs = periodMs;
      if (ext.isController && ext.minCycleTimeMs) {
        formComponent.settings.minCycleTimeMs = ext.minCycleTimeMs;
      }
      //if there is a default cable id set it here
      if (option.defaultCableID) {
        setCableID(option.defaultCableID);
      }
    }
  };

  const handlePositionChanged = (event: any) => {
    setCableID(0)
    setExpansionLine(0)
    let f = cloneDeep(formComponent);
    //split the string
    let split: string[] = event.target.value.toString().split(":")
    // pop the addres off of the end of the array
    f.settings.address = parseInt(split.pop() ?? "0")
    // pop the address type out of the array next
    f.settings.addressType = parseInt(split.pop() ?? "0")
    // f.settings.address = event.target.value
    //   .toString()
    //   .split(":")
    //   .pop();
    setFormComponent(f);
  };

  const getAvailableMenuItemPositions = (type: quack.ComponentType, subtype: number) => {
    const addressTypes = getAddressTypes(type, subtype);

    let availableMenuItemPositions = [];
    for (let i = 0; i < addressTypes.length; i++) {
      let addressType = addressTypes[i];
      let availablePositions = getAvailablePositions(addressType, type);

      availableMenuItemPositions.push(
        <MenuItem key={addressType} divider disabled>
          {getFriendlyAddressTypeName(addressType)}
        </MenuItem>
      );

      for (let j = 0; j < availablePositions.length; j++) {
        availableMenuItemPositions.push(
          <MenuItem
            key={i.toString() + "-" + j.toString()}
            value={addressType + ":" + availablePositions[j].toString()}>
            {getHumanReadableAddress(
              addressType,
              type,
              availablePositions[j],
              device.settings.product
            )}
          </MenuItem>
        );
      }
    }

    return availableMenuItemPositions;
  };

  const toggleOverlays = () => {
    let f = cloneDeep(formComponent);
    f.settings.hasOverlays = !f.settings.hasOverlays;
    setFormComponent(f);
  };

  const title = () => {
    if (mode === "add") {
      return (
        <DialogTitle id="add-component-dialog-title">
          Add Component
          <Typography variant="body2" color="textSecondary">
            {device.name()} - ID: {device.id()}
          </Typography>
        </DialogTitle>
      );
    }

    return (
      <DialogTitle id="component-settings-dialog-title">
        {formComponent.name()} Settings
        <Typography variant="body2" color="textSecondary">
          {formComponent.subTypeName()}
        </Typography>
        <Typography variant="body2" color="textSecondary">
          {device.name()} - ID: {device.id()}
        </Typography>
      </DialogTitle>
    );
  };

  const content = () => {
    if (mode === "add") {
      return addForm();
    }
    return (
      <DialogContent>
        <ComponentForm
          component={formComponent}
          device={device}
          canEdit={canEdit}
          componentChanged={(formComp, isValid) => {
            formComponent.settings = formComp.settings;
            setFormValid(isValid);
          }}
        />
      </DialogContent>
    );
  };

  const isCableComponent = () => {
    return (formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE ||
              formComponent.settings.type ===
                quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE ||
              formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE ||
              (formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_CAPACITOR_CABLE &&
                formComponent.subType() ===
                  quack.CapacitorCableSubtype.CAPACITOR_CABLE_SUBTYPE_FROG))
  }

  const supportsExpansion = () => {
    return (formComponent.settings.type === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE &&
            formComponent.settings.addressType === quack.AddressType.ADDRESS_TYPE_I2C)
  }

  const addForm = () => {
    return (
      <DialogContent>
        {activeStep === 0 ? (
          <React.Fragment>
            <SearchSelect
              selected={componentType}
              changeSelection={handleTypeChanged}
              label="Type"
              options={componentTypeOptions}
              group
            />
            <TextField
              select
              fullWidth
              required
              id="position"
              name="position"
              label="Position"
              value={
                formComponent.settings.addressType + ":" + formComponent.settings.address.toString()
              }
              onChange={handlePositionChanged}
              margin="normal"
              autoFocus={false}
              disabled={
                !isAddressValid(formComponent) ||
                isSingular(formComponent.settings.addressType, formComponent.settings.type)
              }
              helperText={
                isComponentTypeValid(formComponent.settings.type)
                  ? hasAvailablePositions(formComponent)
                    ? isSingular(formComponent.settings.addressType, formComponent.settings.type) ||
                      formComponent.settings.address >= 0
                      ? ""
                      : "* Please select a position *"
                    : "No positions available for " +
                      getFriendlyName(formComponent.settings.type) +
                      " components"
                  : "* Position depends on the type *"
              }
              error={
                isComponentTypeValid(formComponent.settings.type) &&
                !hasAvailablePositions(formComponent)
              }
              variant="outlined"
              InputLabelProps={{ shrink: true }}
              SelectProps={{ className: classes.selectInput }}>
              {getAvailableMenuItemPositions(
                formComponent.settings.type,
                formComponent.settings.subtype
              )}
            </TextField>
            {supportsExpansion() && setExpLine()}
            {(isCableComponent() && !supportsExpansion())&& setComponentAddrType()}
          </React.Fragment>
        ) : activeStep === 1 ? (
          <ComponentForm
            component={formComponent}
            device={device}
            canEdit={canEdit}
            componentChanged={(formComp, isValid) => {
              formComponent.settings = formComp.settings;
              setFormValid(isValid);
            }}
          />
        ) : null}

        <Stepper activeStep={activeStep} className={classes.stepper}>
          <Step key={0}>
            <StepLabel>Required</StepLabel>
          </Step>
          <Step key={1}>
            <StepLabel
              optional={
                <Typography variant="caption" color="textSecondary">
                  Optional
                </Typography>
              }>
              General
            </StepLabel>
          </Step>
        </Stepper>
      </DialogContent>
    );
  };

  const setExpLine = () => {
    return (
      <TextField
        label="Expansion Line"
        type="number"
        margin="normal"
        error={expansionLine < 1 || expansionLine > 12}
        fullWidth
        variant="outlined"
        value={expansionLine}
        helperText="Enter line the cable is connected to on your expander"
        onChange={e => {
          let number = parseInt(e.target.value);
          if (number < 0 || isNaN(number)) number = 0;
          if (number > 12) number = 12;
          setExpansionLine(number);
        }}
      />
    );
  };

  const setComponentAddrType = () => {
    return (
      <TextField
        label="Cable ID"
        type="number"
        margin="normal"
        fullWidth
        variant="outlined"
        value={cableID}
        InputLabelProps={{ shrink: true }}
        helperText="Enter cable ID, 0 for auto"
        onChange={e => {
          let number = parseInt(e.target.value);
          if (number < 0 || isNaN(number)) number = 0;
          if (number > 100) number = 100;
          setCableID(number);
        }}
      />
    );
  };

  const createNewOverlay = () => {
    let f = cloneDeep(formComponent);
    f.settings.overlays.push(
      pond.ComponentOverlays.create({
        min: 0,
        max: 0,
        colour: "#" + Math.floor(Math.random() * 16777215).toString(16),
        message: "",
        measurementType: getMeasurements(formComponent.type(), formComponent.subType())[0]
          .measurementType
      })
    );
    setFormComponent(f);
  };

  const removeOverlay = (index: number) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays.splice(index, 1);
    setFormComponent(f);
  };

  const changeOverlayMin = (index: number, min: number) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays[index].min = min;
    setFormComponent(f);
  };

  const changeOverlayMax = (index: number, max: number) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays[index].max = max;
    setFormComponent(f);
  };

  const changeOverlayMessage = (index: number, message: string) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays[index].message = message;
    setFormComponent(f);
  };

  const changeOverlayColour = (index: number, colour: string) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays[index].colour = colour;
    setFormComponent(f);
  };

  const changeMeasurementType = (index: number, type: quack.MeasurementType) => {
    let f = cloneDeep(formComponent);
    f.settings.overlays[index].measurementType = type;
    setFormComponent(f);
  };

  const overlayGroup = () => {
    //const { component } = form;
    let types = getMeasurements(formComponent.type(), formComponent.subType());
    const groups = [];
    for (let i = 0; i < formComponent.settings.overlays.length; i++) {
      groups[i] = (
        <React.Fragment key={"overlay" + i}>
          <Grid size={{ xs: 6, sm: 6 }}>
            <TextField
              id="min"
              label="Minimum"
              disabled={!formComponent.settings.hasOverlays}
              value={formComponent.settings.overlays[i].min}
              onChange={e => changeOverlayMin(i, +e.target.value)}
              margin="normal"
              fullWidth
              type="number"
              variant="outlined"
            />
            <TextField
              id="max"
              label="Maximum"
              disabled={!formComponent.settings.hasOverlays}
              value={formComponent.settings.overlays[i].max}
              onChange={e => changeOverlayMax(i, +e.target.value)}
              margin="normal"
              fullWidth
              type="number"
              variant="outlined"
            />
            <TextField
              id="message"
              label="message"
              disabled={!formComponent.settings.hasOverlays}
              value={formComponent.settings.overlays[i].message}
              onChange={e => changeOverlayMessage(i, e.target.value)}
              margin="normal"
              fullWidth
              type="text"
              variant="outlined"
            />
          </Grid>
          <Grid size={{ xs: 6, sm: 6 }}>
            <Grid container alignContent="center">
              <Grid size={{ xs: 12, sm: 12 }} style={{ marginBottom: 30 }}>
                <TextField
                  select
                  id="measurementType"
                  required={true}
                  helperText="Measurement"
                  disabled={!formComponent.settings.hasOverlays}
                  value={formComponent.settings.overlays[i].measurementType}
                  onChange={event => changeMeasurementType(i, +event.target.value)}
                  autoFocus={false}
                  margin="dense"
                  variant="standard"
                  fullWidth
                  InputLabelProps={{ shrink: true }}>
                  {types.map(type => (
                    <MenuItem key={type.measurementType} value={type.measurementType}>
                      {type.label}
                    </MenuItem>
                  ))}
                </TextField>
              </Grid>
              <Grid size={{ xs: 12, sm: 12 }}>
                <Box
                  width={"100%"}
                  height={50}
                  marginBottom={3}
                  style={{
                    background: formComponent.settings.overlays[i].colour,
                    cursor: "pointer"
                  }}
                  onClick={() => {
                    setOverlayIndex(i);
                    setOverlayCoulourDialog(true);
                  }}
                />
              </Grid>
              <Grid size={{ xs: 12, sm: 12 }}>
                <Tooltip title="Remove Overlay">
                  <Box width={"100%"} style={{ textAlign: "center", padding: 10 }}>
                    <IconButton
                      color="default"
                      disabled={!formComponent.settings.hasOverlays || !canEdit}
                      aria-label="Remove overlay"
                      onClick={() => removeOverlay(i)}
                      className={classNames(classes.redButton)}>
                      <RemoveIcon />
                    </IconButton>
                  </Box>
                </Tooltip>
              </Grid>
            </Grid>
          </Grid>
        </React.Fragment>
      );
    }
    return (
      <React.Fragment>
        <Grid size={{ xs: 12, sm: 12 }}>
          <Grid container alignItems="center">
            <Grid size={{ xs: 6, sm: 6 }}>
              <Tooltip
                title="Creates an indicator for when measurements are within a given range"
                placement="bottom">
                <FormControlLabel
                  control={
                    <Switch
                      checked={formComponent.settings.hasOverlays}
                      onChange={toggleOverlays}
                      name="overlays"
                      aria-label="overlays"
                      color="secondary"
                    />
                  }
                  label="Overlays"
                  labelPlacement="top"
                  className={classes.switchControl}
                  disabled={!canEdit}
                />
              </Tooltip>
            </Grid>
            <Grid size={{ xs: 6, sm: 6 }}>
              <Tooltip title="Create New Overlay">
                <div>
                  <IconButton
                    color="primary"
                    disabled={!formComponent.settings.hasOverlays || !canEdit}
                    aria-label="Add another overlay"
                    onClick={createNewOverlay}
                    className={classNames(classes.greenButton, classes.noPadding)}>
                    <AddIcon />
                  </IconButton>
                </div>
              </Tooltip>
            </Grid>
          </Grid>
        </Grid>
        {groups}
        {formComponent.settings.overlays[overlayIndex] && (
          <ResponsiveDialog
            open={overlayColourDialog}
            onClose={() => setOverlayCoulourDialog(false)}>
            <DialogContent>
              <Box width={200}>
                <ColourPicker
                  colour={formComponent.settings.overlays[overlayIndex].colour}
                  onChange={colour => changeOverlayColour(overlayIndex, colour)}
                />
              </Box>
            </DialogContent>
            <DialogActions>
              <Button onClick={() => setOverlayCoulourDialog(false)} color="primary">
                Done
              </Button>
            </DialogActions>
          </ResponsiveDialog>
        )}
      </React.Fragment>
    );
  };

  const actions = () => {
    return (
      <DialogActions>
        <Grid container justifyContent="space-between" direction="row" width={"100%"}>
          <Grid size={{ xs: 5 }} >
            {mode === "add" ? (
              <Button disabled={activeStep === 0} onClick={stepBack} color="primary">
                Back
              </Button>
            ) : (
              <DeleteButton disabled={!canEdit} onClick={() => setRemoveDialogOpen(true)}>Delete</DeleteButton>
            )}
          </Grid>
          <Grid size={{ xs: 7 }} container justifyContent="flex-end">
            {mode === "add" ? (
              <React.Fragment>
                <Button onClick={close} color="primary">
                  <Typography variant="subtitle2" color="textPrimary">
                    Cancel
                  </Typography>
                </Button>
                {activeStep === steps.length - 1 ? (
                  <Button color="primary" onClick={addComponent} disabled={!formValid}>
                    Submit
                  </Button>
                ) : (
                  <Button color="primary" onClick={stepNext} disabled={!isFormValid()}>
                    Next
                  </Button>
                )}
              </React.Fragment>
            ) : (
              <React.Fragment>
                <CancelSubmit onSubmit={updateComponent} onCancel={close} submitDisabled={!canEdit || !formValid}/>
              </React.Fragment>
            )}
          </Grid>
        </Grid>
      </DialogActions>
    );
  };

  const remove = () => {
    return (
      <Dialog
        open={isDialogOpen}
        onClose={close}
        aria-labelledby="confirm-remove-component-label"
        aria-describedby="confirm-remove-component-description">
        <DialogTitle id="confirm-remove-component-title">Delete Confirmation</DialogTitle>
        <DialogContent>
          <DialogContentText>Are you sure you want to delete this component?</DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={close} color="primary">
            No
          </Button>
          <Button onClick={removeComponent} color="primary">
            Yes
          </Button>
        </DialogActions>
      </Dialog>
    );
  };

  const componentPrefs = () => {
    let nodes;
    if (
      prevComponent &&
      prevComponent.status.measurement[0] &&
      prevComponent.status.measurement[0].values[0] &&
      prevComponent.status.measurement[0].values[0].values
    ) {
      nodes = prevComponent.status.measurement[0].values[0].values;
    }

    return (
      <Box paddingLeft={2} paddingRight={2}>
        <Typography style={{ fontWeight: 650 }}>Nodes to Exclude</Typography>
        {/* node exclusion */}
        {nodes ? (
          <Box>
            {/* if we have how many nodes are found use checkboxes for each node to add to what is excluded */}
            {nodes.map((_, i) => (
              <FormControlLabel
                key={i}
                control={
                  <Checkbox
                    checked={excludedNodes.includes(i)}
                    onChange={(e, checked) => {
                      let exclNodes = cloneDeep(excludedNodes);
                      if (checked) {
                        exclNodes.push(i);
                      } else {
                        exclNodes.splice(exclNodes.indexOf(i), 1);
                      }
                      setExcludedNodes(exclNodes);
                    }}
                  />
                }
                label={"Node " + (i + 1)}
              />
            ))}
          </Box>
        ) : (
          <Box>
            <Box marginBottom={2}>
              <Typography>
                Cannot determine number of nodes as the component has not taken a measurement yet.
                If you know the number of nodes and which ones you would like to exclude you may
                enter them below. Note that the nodes are 0 based so to exclude the first node you
                would enter 0
              </Typography>
            </Box>
            <Grid
              container
              direction="row"
              justifyContent="space-between"
              alignContent="center"
              alignItems="center">
              {/* if we don't have how many nodes the component has use a entry box to enter the number of the node you wnat to exclude */}
              <Grid size={{ xs: 12 }}>
                <Typography>Excluded Nodes: {excludedNodes.toString()}</Typography>
              </Grid>
              <Grid>
                <TextField
                  type="number"
                  variant="outlined"
                  InputProps={{ inputProps: { min: 0 } }}
                  value={nodeToExclude}
                  onChange={e => {
                    setNodeToExclude(+e.target.value);
                  }}
                />
              </Grid>
              <Grid>
                <Button
                  onClick={() => {
                    let eNodes = cloneDeep(excludedNodes);
                    if (!eNodes.includes(nodeToExclude)) {
                      eNodes.push(nodeToExclude);
                    }
                    setExcludedNodes(eNodes);
                  }}>
                  Add
                </Button>
              </Grid>
            </Grid>
          </Box>
        )}
        <Button
          variant="contained"
          color="primary"
          onClick={() => {
            setExcludedNodes([]);
          }}>
          Clear Excluded Nodes
        </Button>
      </Box>
    );
  };

  return (
    <React.Fragment>
      {mode === "remove" || removeDialogOpen
        ? remove()
        : isDialogOpen && (
            <ResponsiveDialog
              maxWidth="sm"
              fullWidth
              open={isDialogOpen}
              onClose={close}
              scroll="paper">
              {title()}
              <Divider />
              {!isController(formComponent.settings.type) && (
                <Tabs
                  value={tabVal}
                  indicatorColor="primary"
                  textColor="primary"
                  onChange={handleChange}>
                  <Tab label="General" />
                  <Tab label="Overlays" />
                  <Tab label="Nodes" disabled={!prevComponent} />
                </Tabs>
              )}
              <TabPanelMine value={tabVal} index={0}>
                {content()}
              </TabPanelMine>
              <TabPanelMine value={tabVal} index={1}>
                <DialogContent>
                  <Grid
                    container
                    direction="row"
                    justifyContent="space-between"
                    alignItems="center"
                    alignContent="center"
                    spacing={1}>
                    {overlayGroup()}
                  </Grid>
                </DialogContent>
              </TabPanelMine>
              <TabPanelMine value={tabVal} index={2}>
                {componentPrefs()}
              </TabPanelMine>
              {actions()}
            </ResponsiveDialog>
          )}
    </React.Fragment>
  );
}
