import { useEffect, useState } from "react";
import {
  Box,
  Button,
  Card,
  FormControl,
  FormControlLabel,
  FormLabel,
  Grid2 as Grid,
  InputAdornment,
  Radio,
  RadioGroup,
  Slider,
  Switch,
  TextField,
  Typography
} from "@mui/material";
//import MaterialTable from "material-table";
//import { getTableIcons } from "common/ResponsiveTable";
import CableDisplay from "./cableDisplay";
import { distanceConversion, getDistanceUnit } from "utils";
import { pond } from "protobuf-ts/pond";
import CableQuote from "./cableQuote";
import { useMobile } from "hooks";
import { Cable, CableSum, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
import BinSelector from "bin/BinSelector";
import { cloneDeep } from "lodash";
import {
  ConeVolume,
  CylinderVolume,
  RadiansToDegrees,
  TriangleOppositeLength
} from "common/TrigFunctions";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import { makeStyles } from "@mui/styles";

const useStyles = makeStyles(() => ({
    sliderThumb: {
      // height: 15,
      // width: 15,
      marginTop: 0,
      marginLeft: 0,
      //backgroundColor: "yellow"
    },
    // sliderValLabel: {
    //   left: "calc(-50%)",
    //   top: 22,
    //   "& *": {
    //     background: "transparent",
    //     color: "#fff"
    //   }
    // }
}))

export default function CableEstimator() {
  //the conversion constant to convert cubic feet to bushels
  const conversionConstantFT = 0.7786;
  const classes = useStyles();
  const [binOptions, setBinOptions] = useState<jsonBin[]>([]);
  const [displayedRows, setDisplayedRows] = useState<jsonBin[]>([]);
  const [tablePage, setTablePage] = useState(0)
  const [pageSize, setPageSize] = useState(10)
  const [rowCount, setRowCount] = useState(0)
  const [orderBy, setOrderBy] = useState<string>("")
  const [order, setOrder] = useState<"asc" | "desc">("asc")
  const [selectedBin, setSelectedBin] = useState<jsonBin | undefined>();
  const [quoteOpen, setQuoteOpen] = useState(false);
  const [useCustomBin, setUseCustomBin] = useState(false);
  const [diameterFormEntry, setDiameterFormEntry] = useState(
    getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
  );
  //const [capacityFormEntry, setCapacityFormEntry] = useState("0");
  const [ringsFormEntry, setRingsFormEntry] = useState("0");
  const [ringHeightFormEntry, setRingHeightFormEntry] = useState("0");
  const [ringHeightFt, setRingHeightFt] = useState(0);
  const [sidewallFormEntry, setSidewallFormEntry] = useState(
    getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7" : "23"
  );
  const [peakFormEntry, setPeakFormEntry] = useState(
    getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
  );
  //const [eaveToPeakFormEntry, setEaveToPeakFormEntry] = useState("0");
  const [roofAngleFormEntry, setRoofAngleFormEntry] = useState(
    getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7.6" : "25"
  );
  const [hopperAngleFormEntry, setHopperAngleFormEntry] = useState("0");
  const nodeSpacing = 4;
  const [customBin, setCustomBin] = useState<jsonBin>({
    ID: 0,
    Manufacturer: "",
    Type: "Farm", //all bins are currently farm use
    Bottom: "Flat Bottom",
    Diameter: 30,
    Name: "",
    Model: "",
    Capacity: 13942,
    Rings: 0,
    Sidewall: 23,
    Peak: 30, //absolute total height from the ground to the peak of the cone
    EaveToPeak: 0, //the length along the roof from the peak to the eave (not actually used anywhere at the moment)
    RoofAngle: 25,
    HopperAngle: 0,
    CableSums: [],
    Cables: []
  });
  const isMobile = useMobile();
  const [tableSearch, setTableSearch] = useState("")
  const [loading, setLoading] = useState(false)

  const columns: Column<jsonBin>[] = [
    {
      title: "Manufacturer",
      sortKey: "Manufacturer",
      render: (row: jsonBin) => <Box padding={2}>{row.Manufacturer}</Box>
    },
    {
      title: "Model",
      sortKey: "Model",
      render: (row: jsonBin) => <Box padding={2}>{row.Model}</Box>
    },
    {
      title: "Capacity",
      sortKey: "Capacity",
      render: (row: jsonBin) => <Box padding={2}>{row.Capacity}</Box>
    },
    {
      title: "Hopper Angle",
      sortKey: "HopperAngle",
      render: (row: jsonBin) => <Box padding={2}>{row.HopperAngle}</Box>
    },
    {
      title: "Diameter " + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
      sortKey: "Diameter",
      render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Diameter).toFixed(2)}</Box>
    },
    {
      title: "Sidewall" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
      sortKey: "Sidewall",
      render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Sidewall).toFixed(2)}</Box>
    },
    {
      title: "Peak Height" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
      sortKey: "Peak",
      render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Peak).toFixed(2)}</Box>
    },
    {
      title: "Eave To Peak" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
      sortKey: "EaveToPeak",
      render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.EaveToPeak).toFixed(2)}</Box>
    },
    {
      title: "Roof Angle",
      sortKey: "RoofAngle",
      render: (row: jsonBin) => <Box padding={2}>{row.RoofAngle}</Box>
    },
    {
      title: "Rings",
      sortKey: "Rings",
      render: (row: jsonBin) => <Box padding={2}>{row.Rings}</Box>
    }
  ]

  useEffect(()=>{
    setLoading(true)
    //create a clone to manipulate
    let clone: jsonBin[] = cloneDeep(binOptions)
    //having the search filter in here is quite inefficient as it will filter each time you change pages as well 
    //TODO: re-work the filter so it only filters when the search is changed
    
    // sort the array according to orderBy
    clone.sort((a, b) => {
      if (Object.keys(a).includes(orderBy)) {
        let by = orderBy as keyof jsonBin
        if (typeof(a[by]) === "string") {
          // return a.localeCompare(b)
          return (a[by].localeCompare(b[by] as string))
        }
        return ((b[by] as any) - (a[by] as any))
      }
      return 0
    })
    if (order === "desc") clone.reverse()

    if(tableSearch !== ""){
      //filter the data in the cloned list
      clone = clone.filter(bin => {
        //doing a partial search so if any string contains the search string it will return true
        const lowerSearch = tableSearch.toLowerCase()
        if(bin.Manufacturer.toLocaleLowerCase().includes(lowerSearch)) return true
        if(bin.Model.toLowerCase().includes(lowerSearch)) return true
        if(bin.Capacity.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.HopperAngle.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.Diameter.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.Sidewall.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.Peak.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.EaveToPeak.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.RoofAngle.toString().toLowerCase().includes(lowerSearch)) return true
        if(bin.Rings.toString().toLowerCase().includes(lowerSearch)) return true
        return false
      })
    }
    setRowCount(clone.length)
    //split out the first x amount for the page
    let rows = clone.splice(tablePage * pageSize, pageSize)
    setDisplayedRows(rows)
    setLoading(false)
  },[binOptions, tablePage, pageSize, tableSearch, orderBy, order])

  const binOpTable = () => {
    return (
      <ResponsiveTable<jsonBin>
        title={<Typography style={{ fontSize: 20, fontWeight: 650 }}>Bins</Typography>}
        isLoading={loading}
        setSearchText={(search) => {setTableSearch(search)}}
        onRowClick={(bin) => {
          setSelectedBin(bin);
        }}
        page={tablePage}
        columns={columns}
        pageSize={pageSize}
        setPage={(page) => {setTablePage(page)}}
        handleRowsPerPageChange={(e) => {setPageSize(e.target.value)}}
        rows={displayedRows}
        total={rowCount}
        order={order}
        setOrder={setOrder}
        orderBy={orderBy}
        setOrderBy={setOrderBy}
      />
    );
  };

  const cableSummaries = () => {
    //numbers in the summaries are in feet
    let summaries: CableSum[] = [];
    if (customBin.Diameter < 24) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
    } else if (customBin.Diameter < 36) {
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 7,
        NumberOfCables: 3,
        Bracket: 0
      });
    } else if (customBin.Diameter < 42) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 9,
        NumberOfCables: 3,
        Bracket: 0
      });
    } else if (customBin.Diameter < 48) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 14,
        NumberOfCables: 4,
        Bracket: 0
      });
    } else if (customBin.Diameter < 54) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 16,
        NumberOfCables: 5,
        Bracket: 0
      });
    } else if (customBin.Diameter < 60) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 18,
        NumberOfCables: 6,
        Bracket: 0
      });
    } else if (customBin.Diameter < 72) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 20,
        NumberOfCables: 7,
        Bracket: 0
      });
    } else if (customBin.Diameter < 78) {
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 10,
        NumberOfCables: 4,
        Bracket: 0
      });
      summaries.push({
        Orbit: 2,
        DistanceFromCenter: 27,
        NumberOfCables: 9,
        Bracket: 0
      });
    } else if (customBin.Diameter < 90) {
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 10,
        NumberOfCables: 4,
        Bracket: 0
      });
      summaries.push({
        Orbit: 2,
        DistanceFromCenter: 29,
        NumberOfCables: 10,
        Bracket: 0
      });
    } else if (customBin.Diameter < 105) {
      summaries.push({
        Orbit: 0,
        DistanceFromCenter: 2,
        NumberOfCables: 1,
        Bracket: 0
      });
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 18,
        NumberOfCables: 6,
        Bracket: 0
      });
      summaries.push({
        Orbit: 2,
        DistanceFromCenter: 36,
        NumberOfCables: 12,
        Bracket: 0
      });
    } else {
      //diameter is 105 or larger
      summaries.push({
        Orbit: 1,
        DistanceFromCenter: 9,
        NumberOfCables: 3,
        Bracket: 0
      });
      summaries.push({
        Orbit: 2,
        DistanceFromCenter: 26.5,
        NumberOfCables: 9,
        Bracket: 0
      });
      summaries.push({
        Orbit: 3,
        DistanceFromCenter: 44,
        NumberOfCables: 14,
        Bracket: 0
      });
    }

    return summaries;
  };

  const buildCables = () => {
    let bin = cloneDeep(customBin);
    let binRadius = bin.Diameter / 2;
    //use the diameter of the bin to build the cable summaries (orbit information)
    let sums = cableSummaries();

    //then use the orbits and the rest of the bins dimensions to build the cables
    let hasCenter = false;
    let roofRadians = bin.RoofAngle * (Math.PI / 180);
    let hopperRadians = bin.HopperAngle * (Math.PI / 180);
    let newCables: Cable[] = [];

    sums.forEach((sum, i) => {
      if (i === 0) {
        hasCenter = true;
      }
      let hopperHeight = 0;
      // calculate the hight of the cone section of the cable here
      let topHeight = (binRadius - sum.DistanceFromCenter) * Math.tan(roofRadians);
      //if the hopper angle is greater than 0 calculate the hopper height for the orbit
      if (bin.HopperAngle > 0) {
        hopperHeight = (binRadius - sum.DistanceFromCenter) * Math.tan(hopperRadians);
      }

      //get the maximum value for the top of the bin to the botton
      let maxCablelength = Math.round((topHeight + bin.Sidewall + hopperHeight) * 10) / 10;

      //shorten cable for the clearance from the bottom and round the cable down to the nearest even number
      let lenX10 = (maxCablelength - 2) * 10;
      let cableLen = (lenX10 - (lenX10 % 20)) / 10;

      //set the bracket in the cableSum based on the length of the cable and whether the bin has a center cable
      if (cableLen < 36) {
        sum.Bracket = 3;
      } else {
        if (hasCenter) {
          sum.Bracket = 2;
        } else {
          sum.Bracket = 1;
        }
      }

      // divide the cable by the node spacing to get the number of nodes
      let sensors = Math.ceil(cableLen / nodeSpacing);

      //add in the cables for each orbit
      //moisture cables
      var moistureCables: Cable = {
        Orbit: sum.Orbit,
        Length: cableLen,
        Nodes: sensors,
        Type: 2,
        Count: 1
      };
      newCables.push(moistureCables);
      //temp Cables
      if (sum.NumberOfCables > 1) {
        let tempCables: Cable = {
          Orbit: sum.Orbit,
          Length: cableLen,
          Nodes: sensors,
          Type: 1,
          Count: sum.NumberOfCables - 1
        };
        newCables.push(tempCables);
      }
    });

    //add the summaries and cables to the bin
    bin.CableSums = sums;
    bin.Cables = newCables;
    console.log(bin);
    setCustomBin(bin);
  };

  const calcRoofAngle = (binRad: number, topConeHeight: number) => {
    //calculate the angle using the the two given sides of a right triangle
    let angle = RadiansToDegrees(Math.atan(topConeHeight / binRad)); //('arcTan(opposite / adjacent))' and convert to degrees
    angle = Math.round(angle * 100) / 100; // round to 2 digits
    return angle;
  };

  const calcConeHeight = (binRad: number, roofAngle: number) => {
    return TriangleOppositeLength(binRad, roofAngle);
  };

  /**
   * takes in the dimensions of the bin to calculate its bushel capacity
   * @param diameter
   * @param topConeHeight
   * @param sidewallHeight
   * @param hopperHeight
   * @returns the bushel capacity of the bin with given dimensions
   */
  const advancedGrainCalc = (bin: jsonBin) => {
    let tcH = bin.Peak - bin.Sidewall;
    let sH = bin.Sidewall;
    let hH = TriangleOppositeLength(bin.Diameter / 2, bin.HopperAngle); //get the height of the hopper since it is not stored in the bin data
    let d = bin.Diameter;

    //calculate the volumes and convert them to bushels
    let topConeBushels = ConeVolume(d / 2, tcH) * conversionConstantFT;
    let sidewallBushels = CylinderVolume(d / 2, sH) * conversionConstantFT;
    let hopperBushels = ConeVolume(d / 2, hH ?? 0) * conversionConstantFT;

    return Math.round(topConeBushels + sidewallBushels + hopperBushels);
  };

  const customBinForm = () => {
    return (
      <Card style={{ padding: 20 }}>
        <Grid container spacing={2}>
          {/* first row */}
          <Grid size={{xs:12, md:4}}>
            <TextField
              variant="outlined"
              fullWidth
              label="Bin Manufacturer"
              value={customBin.Manufacturer}
              onChange={e => {
                let bin = cloneDeep(customBin);
                bin.Manufacturer = e.target.value;
                setCustomBin(bin);
              }}
            />
          </Grid>
          <Grid size={{xs:12, md:4}}>
            <TextField
              variant="outlined"
              fullWidth
              label="Bin Name"
              value={customBin.Name}
              onChange={e => {
                let bin = cloneDeep(customBin);
                bin.Name = e.target.value;
                setCustomBin(bin);
              }}
            />
          </Grid>
          <Grid size={{xs:12, md:4}}>
            <TextField
              variant="outlined"
              fullWidth
              label="Bin Model"
              value={customBin.Model}
              onChange={e => {
                let bin = cloneDeep(customBin);
                bin.Model = e.target.value;
                setCustomBin(bin);
              }}
            />
          </Grid>
          {/* second row */}
          <Grid size={{xs:12, md:4}}>
            <TextField
              type="number"
              fullWidth
              variant="outlined"
              label="Diameter"
              helperText={"The full diameter of the bin"}
              InputProps={{
                endAdornment: (
                  <InputAdornment position="end">
                    {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
                  </InputAdornment>
                )
              }}
              value={diameterFormEntry}
              error={isNaN(parseFloat(diameterFormEntry))}
              onChange={e => {
                setDiameterFormEntry(e.target.value);
                let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
                if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                  val = val * 3.281;
                }
                //when the diameter is changed use the current peak height to adjust the roof angle
                let bin = cloneDeep(customBin);
                bin.Diameter = val;
                let newAngle = calcRoofAngle(bin.Diameter / 2, bin.Peak - bin.Sidewall);
                setRoofAngleFormEntry(newAngle.toString());
                bin.RoofAngle = newAngle;
                bin.Capacity = advancedGrainCalc(bin);
                setCustomBin(bin);
              }}
            />
          </Grid>
          <Grid size={{xs:12, md:6}}>
            <TextField
              type="number"
              fullWidth
              variant="outlined"
              label="Peak Height"
              InputProps={{
                endAdornment: (
                  <InputAdornment position="end">
                    {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
                  </InputAdornment>
                )
              }}
              helperText={
                "total height from the bottom of the sidewall to the top of the roof, calculated from the diameter, roof angle, and sidewall height of the bin"
              }
              value={peakFormEntry}
              error={isNaN(parseFloat(peakFormEntry))}
              onChange={e => {
                setPeakFormEntry(e.target.value);
                let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
                if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                  val = val * 3.281;
                }
                //when the peak height is changed use the diameter to calculate the roof angle
                let bin = cloneDeep(customBin);
                bin.Peak = val;
                let newAngle = calcRoofAngle(bin.Diameter / 2, bin.Peak - bin.Sidewall);
                setRoofAngleFormEntry(newAngle.toString());
                bin.RoofAngle = newAngle;
                bin.Capacity = advancedGrainCalc(bin);
                setCustomBin(bin);
              }}
            />
          </Grid>
          {/* third row */}
          <Grid size={{xs:12, md:4}}>
            <TextField
              type="number"
              fullWidth
              variant="outlined"
              label="Rings"
              helperText={"Number of rings along the sidewall"}
              value={ringsFormEntry}
              error={isNaN(parseFloat(ringsFormEntry))}
              onChange={e => {
                setRingsFormEntry(e.target.value);
                let bin = cloneDeep(customBin);
                let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
                bin.Rings = val;
                //use the new number of rings and ring height to get the sidewall height
                let sidewallFt = val * ringHeightFt;
                bin.Sidewall = sidewallFt;
                if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                  setSidewallFormEntry((sidewallFt / 3.281).toString());
                } else {
                  setSidewallFormEntry(sidewallFt.toString());
                }
                //with the sidewall height changing the roof ange should also change
                let newAngle = calcRoofAngle(bin.Diameter / 2, bin.Peak - bin.Sidewall);
                setRoofAngleFormEntry(newAngle.toString());
                bin.RoofAngle = newAngle;
                bin.Capacity = advancedGrainCalc(bin);
                setCustomBin(bin);
              }}
            />
          </Grid>
          <Grid size={{xs:12, md:4}}>
            <TextField
              type="number"
              fullWidth
              variant="outlined"
              label="Height of Ring"
              helperText={"The Height of a single ring/band of the bin"}
              InputProps={{
                endAdornment: <InputAdornment position="end">{"in"}</InputAdornment>
              }}
              value={ringHeightFormEntry}
              error={isNaN(parseFloat(ringHeightFormEntry))}
              onChange={e => {
                setRingHeightFormEntry(e.target.value);
                let inVal = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
                // if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                //   val = val * 3.281;
                // }
                let ringFt = inVal / 12;
                setRingHeightFt(ringFt);
                //based on this entry and the number of rings calculate the sidwall
                let bin = cloneDeep(customBin);
                let sidewallFt = bin.Rings * ringFt;
                bin.Sidewall = sidewallFt;
                if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                  setSidewallFormEntry((sidewallFt / 3.281).toString());
                } else {
                  setSidewallFormEntry(sidewallFt.toString());
                }
                //with the sidewall height changing the roof angle should also change with it
                let newAngle = calcRoofAngle(bin.Diameter / 2, bin.Peak - bin.Sidewall);
                setRoofAngleFormEntry(newAngle.toString());
                bin.RoofAngle = newAngle;
                bin.Capacity = advancedGrainCalc(bin);
                setCustomBin(bin);
              }}
            />
          </Grid>
          <Grid size={{xs:12, md:4}}>
            <TextField
              type="number"
              fullWidth
              variant="outlined"
              label="Bin Sidewall Height"
              helperText={"Full height of all of the rings together"}
              InputProps={{
                endAdornment: (
                  <InputAdornment position="end">
                    {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
                  </InputAdornment>
                )
              }}
              value={sidewallFormEntry}
              error={isNaN(parseFloat(sidewallFormEntry))}
              onChange={e => {
                //need to handle conversions here
                setSidewallFormEntry(e.target.value);
                let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
                //if the value entered is meters convert it to feet for the bin
                if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                  val = val * 3.281;
                }
                let bin = cloneDeep(customBin);
                bin.Sidewall = val;
                let newAngle = calcRoofAngle(bin.Diameter / 2, bin.Peak - bin.Sidewall);
                setRoofAngleFormEntry(newAngle.toString());
                bin.RoofAngle = newAngle;
                bin.Capacity = advancedGrainCalc(bin);
                setCustomBin(bin);
              }}
            />
          </Grid>
          {/* fourth row */}
          <Grid size={{xs:12, md:6}}>
            <Box display="flex" justifyContent="center" alignItems="center">
              <Slider
                classes={{
                  thumb: classes.sliderThumb,
                  //valueLabel: classes.sliderValLabel
                }}
                valueLabelDisplay="off"
                min={20}
                max={40}
                name="roofAngle"
                aria-label="roofAngle"
                step={0.1}
                color="secondary"
                //track={false}
                value={customBin.RoofAngle}
                onChange={(_, newValue) => {
                  let val = newValue as number;
                  setRoofAngleFormEntry(val.toString());
                  let bin = cloneDeep(customBin);
                  bin.RoofAngle = val;
                  //adjusting the roof angle should also calculate the new top cone and adjust the peak height of the bin
                  let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
                  bin.Peak = bin.Sidewall + coneHeight; //assign it as feet
                  let peakHeightDisplay = bin.Sidewall + coneHeight;
                  if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                    peakHeightDisplay = peakHeightDisplay / 3.281;
                  }
                  setPeakFormEntry(peakHeightDisplay.toFixed(1));
                  bin.Capacity = advancedGrainCalc(bin);
                  setCustomBin(bin);
                }}
              />
              <TextField
                style={{ marginLeft: 10 }}
                type="number"
                variant="outlined"
                label="Roof Angle"
                helperText={"Calculated from diameter, sidewall and peak height. Usually 25-35"}
                InputProps={{
                  endAdornment: <InputAdornment position="end">{"deg"}</InputAdornment>
                }}
                value={roofAngleFormEntry}
                error={isNaN(parseFloat(roofAngleFormEntry))}
                onChange={e => {
                  setRoofAngleFormEntry(e.target.value);
                  let bin = cloneDeep(customBin);
                  bin.RoofAngle = isNaN(parseFloat(e.target.value))
                    ? 0
                    : parseFloat(e.target.value);
                  //adjusting the roof angle should also calculate the new top cone and adjust the peak height of the bin
                  let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
                  bin.Peak = bin.Sidewall + coneHeight;
                  let peakHeightDisplay = bin.Sidewall + coneHeight;
                  if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                    peakHeightDisplay = peakHeightDisplay / 3.281;
                  }
                  setPeakFormEntry(peakHeightDisplay.toFixed(1));
                  bin.Capacity = advancedGrainCalc(bin);
                  setCustomBin(bin);
                }}
              />
            </Box>
          </Grid>
          <Grid size={{xs:12, md:6}}>
            <Box display="flex" justifyContent="center" alignItems="center">
              <Slider
                classes={{
                  thumb: classes.sliderThumb,
                  //valueLabel: classes.sliderValLabel,
                }}
                valueLabelDisplay="off"
                min={20}
                max={40}
                name="hopperAngle"
                aria-label="hopperAngle"
                step={0.1}
                color="secondary"
                disabled={customBin.Bottom === "Flat Bottom"}
                //track={false}
                value={customBin.HopperAngle}
                onChange={(_, newValue) => {
                  setHopperAngleFormEntry(newValue.toString());
                  let bin = cloneDeep(customBin);
                  bin.HopperAngle = newValue as number;
                  bin.Capacity = advancedGrainCalc(bin);
                  setCustomBin(bin);
                }}
              />
              <TextField
                type="number"
                style={{ marginLeft: 10 }}
                fullWidth
                variant="outlined"
                disabled={customBin.Bottom === "Flat Bottom"}
                label="Hopper Angle"
                helperText={"Calculated from the hopper height and diameter"}
                InputProps={{
                  endAdornment: <InputAdornment position="end">{"deg"}</InputAdornment>
                }}
                value={hopperAngleFormEntry}
                error={isNaN(parseFloat(hopperAngleFormEntry))}
                onChange={e => {
                  setHopperAngleFormEntry(e.target.value);
                  let bin = cloneDeep(customBin);
                  bin.HopperAngle = isNaN(parseFloat(e.target.value))
                    ? 0
                    : parseFloat(e.target.value);
                  bin.Capacity = advancedGrainCalc(bin);
                  setCustomBin(bin);
                }}
              />
            </Box>
          </Grid>
          {/* bottom */}
          <Grid>
            <FormControl
              component="fieldset"
              variant="outlined">
              <FormLabel component="legend">Shape</FormLabel>
              <RadioGroup
                aria-label="bin shape"
                name="binShape"
                value={customBin.Bottom}
                onChange={(_, value) => {
                  let bin = cloneDeep(customBin);
                  bin.Bottom = value;
                  if (value === "Hopper Bottom") {
                    bin.HopperAngle = 25;
                    setHopperAngleFormEntry("25");
                  } else {
                    bin.HopperAngle = 0;
                    setHopperAngleFormEntry("0");
                  }
                  bin.Capacity = advancedGrainCalc(bin);
                  setCustomBin(bin);
                }}>
                <FormControlLabel
                  key={"flat"}
                  value={"Flat Bottom"}
                  control={<Radio />}
                  label={"Flat Bottom"}
                />
                <FormControlLabel
                  key={"hopper"}
                  value={"Hopper Bottom"}
                  control={<Radio />}
                  label={"Hopper"}
                />
              </RadioGroup>
              </FormControl>
          </Grid>
        </Grid>
        {/* not strictly necessary for quoting */}
        {/* <TextField
          type="number"
          variant="outlined"
          label="Bin Capacity"
          value={capacityFormEntry}
          error={isNaN(parseFloat(capacityFormEntry))}
          onChange={e => {
            setCapacityFormEntry(e.target.value);
            let bin = cloneDeep(customBin);
            bin.Capacity = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
            setCustomBin(bin);
          }}
        /> */}
        {/* this dimension isn't actually used for anything */}
        {/* <TextField
          type="number"
          variant="outlined"
          label="Eave to Peak"
          value={eaveToPeakFormEntry}
          error={isNaN(parseFloat(eaveToPeakFormEntry))}
          onChange={e => {
            //need to handle conversions here
            setEaveToPeakFormEntry(e.target.value);
            let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
            //if the value entered is meters convert it to feet for the bin
            if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
              val = val * 3.281;
            }
            let bin = cloneDeep(customBin);
            bin.EaveToPeak = val;
            setCustomBin(bin);
          }}
        /> */}
        <Button variant="contained" color="primary" onClick={buildCables}>
          Generate Cables
        </Button>
        <Typography style={{ fontWeight: 650 }}>
          Estimated Capacity: {customBin.Capacity} bushels
        </Typography>
      </Card>
    );
  };

  const binDisplay = () => {
    let displayBin = selectedBin;
    if (useCustomBin) {
      displayBin = customBin;
    }
    if (displayBin) {
      return (
        <CableDisplay
          bin={displayBin}
          updateBin={newBin => {
            setSelectedBin(newBin);
          }}
        />
      );
    }
  };

  const quoteDisplay = () => {
    let displayBin = selectedBin;
    if (useCustomBin) {
      displayBin = customBin;
    }
    if (displayBin) {
      return (
        <CableQuote
          bin={displayBin}
          open={quoteOpen}
          close={() => {
            setQuoteOpen(false);
          }}
        />
      );
    }
  };

  return (
    <Box padding={2}>
      <FormControlLabel
        label="Custom Bin"
        control={
          <Switch
            color="default"
            value={useCustomBin}
            checked={useCustomBin}
            onChange={(_, checked) => {
              setUseCustomBin(checked);
            }}
            name="storage"
          />
        }
      />

      {/* grid  of select boxes for pre-built options */}
      <Grid container direction="row" spacing={2} alignContent="center" alignItems="center">
        {!useCustomBin && (
          <Grid size={isMobile ? 12 : 10}>
            <BinSelector
              optionsChanged={ops => {
                setBinOptions(ops);
              }}
            />
          </Grid>
        )}
        <Grid size={isMobile ? 12 : 2}>
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              setQuoteOpen(true);
            }}>
            Generate Quote
          </Button>
        </Grid>
      </Grid>
      {useCustomBin ? customBinForm() : binOpTable()}
      {/* summary of cable data */}
      {binDisplay()}
      {quoteDisplay()}
    </Box>
  );
}
