import "./PhysicsSimulationBox.scss";
import { FieldView, FieldViewProps } from './FieldView';
import React = require('react');
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { observer } from 'mobx-react';
import "./PhysicsSimulationBox.scss";
import Weight from "./PhysicsSimulationWeight";
import Wall  from "./PhysicsSimulationWall"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { CheckBox } from "../search/CheckBox";
import PauseIcon from "@mui/icons-material/Pause";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import ReplayIcon from "@mui/icons-material/Replay";
import QuestionMarkIcon from "@mui/icons-material/QuestionMark";
import ArrowLeftIcon from "@mui/icons-material/ArrowLeft";
import ArrowRightIcon from "@mui/icons-material/ArrowRight";
import EditIcon from "@mui/icons-material/Edit";
import EditOffIcon from "@mui/icons-material/EditOff";
import {
  Box,
  Button,
  Checkbox,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText,
  DialogActions,
  FormControl,
  FormControlLabel,
  FormGroup,
  IconButton,
  LinearProgress,
  Stack,
} from "@mui/material";
import Typography from "@mui/material/Typography";
import React, { useEffect, useState } from "react";
import "./App.scss";
import { InputField } from "./InputField";
import questions from "./PhysicsSimulationQuestions.json";
import tutorials from "./PhysicsSimulationTutorial.json";
import { IWallProps, Wall } from "./Wall";
import { IForce, Weight } from "./Weight";
interface VectorTemplate {
  top: number;
  left: number;
  width: number;
  height: number;
  x1: number;
  y1: number;
  x2: number;
  y2: number;
  weightX: number;
  weightY: number;
}
interface QuestionTemplate {
  questionSetup: string[];
  variablesForQuestionSetup: string[];
  question: string;
  answerParts: string[];
  answerSolutionDescriptions: string[];
  goal: string;
  hints: { description: string; content: string }[];
}

interface TutorialTemplate {
  question: string;
  steps: {
    description: string;
    content: string;
    forces: {
      description: string;
      magnitude: number;
      directionInDegrees: number;
      component: boolean;
    }[];
    showMagnitude: boolean;
  }[];
}

@observer
export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {

  public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); }

  constructor(props: any) {
    super(props);
  }

  // Constants
  const xMin = 0;
  const yMin = 0;
  const xMax = 100;
  const yMax = 100;
  const color = `rgba(0,0,0,0.5)`;
  const radius = 50;
  const wallPositions: IWallProps[] = [];

  componentDidMount() {
    this.wallPositions.push({ length: 70, xPos: 0, yPos: 0, angleInDegrees: 0 });
    this.wallPositions.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 });
    this.wallPositions.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 });
    this.wallPositions.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 });

    // Used throughout sims
    this.xMax = this.layoutDoc._width*0.08;
    this.yMax = this.layoutDoc._height*0.08;
    this.radius = 0.1*this.layoutDoc._height;
    this.dataDoc.reviewCoefficient = this.dataDoc.reviewCoefficient ?? 0;
    this.dataDoc.questionVariables = this.dataDoc.questionVariables ?? [];
    this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0;
    this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0;
    this.dataDoc.componentForces = this.dataDoc.componentForces ?? [];
    this.dataDoc.displayChange = this.dataDoc.displayChange ?? { xDisplay: 0, yDisplay: 0 };
    this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false;
    this.dataDoc.gravity = this.dataDoc.gravity ?? -9.81;
    this.dataDoc.mass = this.dataDoc.mass ?? 1;
    this.dataDoc.mode = this.dataDoc.mode ?? "Freeform";
    this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0;
    this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0;
    this.dataDoc.resetAll = this.dataDoc.resetAll ?? true;
    this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false;
    this.dataDoc.showComponentForces = this.dataDoc.showComponentForces ?? false;
    this.dataDoc.showForces = this.dataDoc.showForces ?? true;
    this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? true;
    this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false;
    this.dataDoc.simulationPaused = this.dataDoc.simulationPaused ?? true;
    this.dataDoc.simulationReset = this.dataDoc.simulationReset ?? false;
    this.dataDoc.simulationSpeed = this.dataDoc.simulationSpeed ?? 2;
    this.dataDoc.simulationType = this.dataDoc.simulationType ?? "Inclined Plane";
    this.dataDoc.startForces = this.dataDoc.startForces ?? [];
    this.dataDoc.startPosX = this.dataDoc.startPosX ?? 0;
    this.dataDoc.startPosY = this.dataDoc.startPosY ?? 0;
    this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0;
    this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0;
    this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0;
    this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [];
    this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0;
    this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0;

    // Used for review mode
    this.dataDoc.answerInputFields = this.dataDoc.answerInputFields ?? <div></div>;
    this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null;
    this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false;
    this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? [];
    this.dataDoc.hintDialogueOpen = this.dataDoc.hintDialogueOpen ?? false;
    this.dataDoc.noMovement = this.dataDoc.noMovement ?? false;
    this.dataDoc.questionNumber = this.dataDoc.questionNumber ?? 0;
    this.dataDoc.questionPartOne = this.dataDoc.questionPartOne ?? "";
    this.dataDoc.questionPartTwo = this.dataDoc.questionPartTwo ?? "";
    this.dataDoc.reviewGravityAngle = this.dataDoc.reviewGravityAngle ?? 0;
    this.dataDoc.reviewGravityMagnitude = this.dataDoc.reviewGravityMagnitude ?? 0;
    this.dataDoc.reviewNormalAngle = this.dataDoc.reviewNormalAngle ?? 0;
    this.dataDoc.reviewNormalMagnitude = this.dataDoc.reviewNormalMagnitude ?? 0;
    this.dataDoc.reviewStaticAngle = this.dataDoc.reviewStaticAngle ?? 0;
    this.dataDoc.reviewStaticMagnitude = this.dataDoc.reviewStaticMagnitude ?? 0;
    this.dataDoc.selectedSolutions = this.dataDoc.selectedSolutions ?? [];
    this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0];
    this.dataDoc.sketching = this.dataDoc.sketching ?? false;

    // Used for tutorial mode
    this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane;

    // Used for uniform circular motion
    this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150;

    // Used for spring simulation
    this.dataDoc.springConstant = this.dataDoc.springConstant ?? 0.5;
    this.dataDoc.springRestLength = this.dataDoc.springRestLength ?? 200;
    this.dataDoc.springStartLength = this.dataDoc.springStartLength ?? 200;

    // Used for pendulum simulation
    this.dataDoc.adjustPendulumAngle = this.dataDoc.adjustPendulumAngle ?? { angle: 0, length: 0 };
    this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 0;
    this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300;
    this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0;

    // Used for wedge simulation
    this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0;
    this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0;
    this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26;
    this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * 400;
    this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? 400;

    // Used for pulley simulation
    this.dataDoc.positionXDisplay2 = this.dataDoc.positionXDisplay2 ?? 0;
    this.dataDoc.velocityXDisplay2 = this.dataDoc.velocityXDisplay2 ?? 0;
    this.dataDoc.accelerationXDisplay2 = this.dataDoc.accelerationXDisplay2 ?? 0;
    this.dataDoc.positionYDisplay2 = this.dataDoc.positionYDisplay2 ?? 0;
    this.dataDoc.velocityYDisplay2 = this.dataDoc.velocityYDisplay2 ?? 0;
    this.dataDoc.accelerationYDisplay2 = this.dataDoc.accelerationYDisplay2 ?? 0;
    this.dataDoc.startPosX2 = this.dataDoc.startPosX2 ?? 0;
    this.dataDoc.startPosY2 = this.dataDoc.startPosY2 ?? 0;
    this.dataDoc.displayChange2 = this.dataDoc.displayChange2 ?? { xDisplay: 0, yDisplay: 0 };
    this.dataDoc.startForces2 = this.dataDoc.startForces2 ?? [];
    this.dataDoc.updatedForces2 = this.dataDoc.updatedForces2 ?? [];
    this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1;

    // Setup simulation
    if (this.dataDoc.simulationType != "Circular Motion") {
      this.dataDoc.startVelX = 0;
      this.dataDoc.setStartVelY = 0;
      this.dataDoc.velocityXDisplay = (0);
      this.dataDoc.velocityYDisplay = (0);
    }
    if (this.dataDoc.mode == "Freeform") {
      this.dataDoc.showForceMagnitudes = (true);
      if (this.dataDoc.simulationType == "One Weight") {
        this.dataDoc.showComponentForces = false;
        this.dataDoc.startPosY = (this.yMin + this.radius);
        this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - this.radius);
        this.dataDoc.positionYDisplay = (this.getDisplayYPos(this.yMin + this.radius));
        this.dataDoc.positionXDisplay((this.xMax + this.xMin) / 2 - this.radius);
        this.dataDoc.updatedForces = ([
          {
            description: "Gravity",
            magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
            directionInDegrees: 270,
            component: false,
          },
        ]);
        this.dataDoc.startForces = ([
          {
            description: "Gravity",
            magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
            directionInDegrees: 270,
            component: false,
          },
        ]);
        this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
      } else if (this.dataDoc.simulationType == "Inclined Plane") {
        this.changeWedgeBasedOnNewAngle(26);
        this.dataDoc.startForces = ([
          {
            description: "Gravity",
            magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
            directionInDegrees: 270,
            component: false,
          },
        ]);
        this.updateForcesWithFriction(Number(this.dataDoc.coefficientOfStaticFriction));
      } else if (this.dataDoc.simulationType == "Pendulum") {
        this.setupPendulum();
      } else if (this.dataDoc.simulationType == "Spring") {
        this.setupSpring();
      } else if (this.dataDoc.simulationType == "Circular Motion") {
        this.setupCircular(0);
      } else if (this.dataDoc.simulationType == "Pulley") {
        this.setupPulley();
      } else if (this.dataDoc.simulationType == "Suspension") {
        this.setupSuspension();
      }
    } else if (this.dataDoc.mode == "Review") {
      this.dataDoc.showComponentForces = (false);
      this.dataDoc.showForceMagnitudes = (true);
      this.dataDoc.showAcceleration = (false);
      this.dataDoc.showVelocity = (false);
      this.dataDoc.showForces= (true);
      this.generateNewQuestion();
      if (this.dataDoc.simulationType == "One Weight") {
        // TODO - one weight review problems
      } else if (this.dataDoc.simulationType == "Spring") {
        this.setupSpring();
        // TODO - spring review problems
      } else if (this.dataDoc.simulationType == "Inclined Plane") {
        this.dataDoc.updatedForces = ([]);
        this.dataDoc.startForces = ([]);
      } else if (this.dataDoc.simulationType == "Pendulum") {
        this.setupPendulum();
        // TODO - pendulum review problems
      } else if (this.dataDoc.simulationType == "Circular Motion") {
        this.setupCircular(0);
        // TODO - circular motion review problems
      } else if (this.dataDoc.simulationType == "Pulley") {
        this.setupPulley();
        // TODO - pulley tutorial review problems
      } else if (this.dataDoc.simulationType == "Suspension") {
        this.setupSuspension();
        // TODO - suspension tutorial review problems
      }
    } else if (this.dataDoc.mode == "Tutorial") {
      this.dataDoc.showComponentForces = (false);
      this.dataDoc.stepNumber = (0);
      this.dataDoc.showAcceleration = (false);
      if (this.dataDoc.simulationType != "Circular Motion") {
        this.dataDoc.velocityXDisplay = (0);
        setVelocityYDisplay = (0);
        this.dataDoc.showVelocity = (false);
      } else {
        this.dataDoc.velocityXDisplay = (20);
        this.dataDoc.velocityYDisplay = (0);
        this.dataDoc.showVelocity = (true);
      }

      if (this.dataDoc.simulationType == "One Weight") {
        this.dataDoc.showForces = (true);
        this.dataDoc.startPosY = (this.yMax - 100);
        this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - this.radius);
        this.dataDoc.selectedTutorial = (tutorials.freeWeight);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.freeWeight.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.freeWeight.steps[0].showMagnitude);
      } else if (this.dataDoc.simulationType == "Spring") {
        this.dataDoc.showForces = (true);
        this.setupSpring();
        this.dataDoc.startPosY = (this.yMin + 200 + 19.62);
        this.dataDoc.startPosX = ((this.xMax + this.xMin) / 2 - this.radius);
        this.dataDoc.selectedTutorial = (tutorials.spring);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.spring.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.spring.steps[0].showMagnitude);
      } else if (this.dataDoc.simulationType == "Pendulum") {
        this.dataDoc.showForces = (true);
        const length = 300;
        const angle = 30;
        const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
        const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
        const xPos = this.xMax / 2 - x - this.radius;
        const yPos = y - this.radius - 5;
        this.dataDoc.startPosX = (xPos);
        this.dataDoc.startPosY = (yPos);
        this.dataDoc.selectedTutorial = (tutorials.pendulum);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.pendulum.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.pendulum.steps[0].showMagnitude);
        this.dataDoc.pendulumAngle = (30);
        this.dataDoc.pendulumLength = (300);
        this.dataDoc.adjustPendulumAngle = ({ angle: 30, length: 300 });
      } else if (this.dataDoc.simulationType == "Inclined Plane") {
        this.dataDoc.showForces = (true);
        this.dataDoc.wedgeAngle = (26);
        this.changeWedgeBasedOnNewAngle(26);
        this.dataDoc.selectedTutorial = (tutorials.inclinePlane);
        this.dataDoc.startForces = (
          this.getForceFromJSON(tutorials.inclinePlane.steps[0].forces)
        );
        this.dataDoc.showForceMagnitudes = (tutorials.inclinePlane.steps[0].showMagnitude);
      } else if (this.dataDoc.simulationType == "Circular Motion") {
        this.dataDoc.showForces = (true);
        this.setupCircular(40);
        this.dataDoc.selectedTutorial = (tutorials.circular);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.circular.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.circular.steps[0].showMagnitude);
      } else if (simulationType == "Pulley") {
        this.dataDoc.showForces = (true);
        this.setupPulley();
        this.dataDoc.selectedTutorial = (tutorials.pulley);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.pulley.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.pulley.steps[0].showMagnitude);
      } else if (this.dataDoc.simulationType == "Suspension") {
        this.dataDoc.showForces = (true);
        this.setupSuspension();
        this.dataDoc.selectedTutorial = (tutorials.suspension);
        this.dataDoc.startForces = (this.getForceFromJSON(tutorials.suspension.steps[0].forces));
        this.dataDoc.showForceMagnitudes = (tutorials.suspension.steps[0].showMagnitude);
      }
      this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
    }
  }

  componentDidUpdate() {
    this.xMax = this.layoutDoc._width*0.08;
    this.yMax = this.layoutDoc._height*0.08;
    this.radius = 0.1*this.layoutDoc._height;
  }

  // Helper function to go between display and real values
  getDisplayYPos = (yPos: number) => {
    return this.yMax - this.dataDoc.yPos - 2 * this.radius + 5;
  };
  getYPosFromDisplay = (yDisplay: number) => {
    return this.yMax - this.dataDoc.yDisplay - 2 * this.radius + 5;
  };

  // Update forces when coefficient of static friction changes in freeform mode
  updateForcesWithFriction = (
    coefficient: number,
    width: number = this.wedgeWidth,
    height: number = this.wedgeHeight
  ) => {
    const normalForce: IForce = {
      description: "Normal Force",
      magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass,
      directionInDegrees:
        180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
      component: false,
    };
    let frictionForce: IForce = {
      description: "Static Friction Force",
      magnitude:
        coefficient *
        Math.abs(this.gravity) *
        Math.cos(Math.atan(height / width)) *
        this.mass,
      directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
      component: false,
    };
    // reduce magnitude or friction force if necessary such that block cannot slide up plane
    let yForce = -Math.abs(this.gravity) * this.mass;
    yForce +=
      normalForce.magnitude *
      Math.sin((normalForce.directionInDegrees * Math.PI) / 180);
    yForce +=
      frictionForce.magnitude *
      Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
    if (yForce > 0) {
      frictionForce.magnitude =
        (-normalForce.magnitude *
          Math.sin((normalForce.directionInDegrees * Math.PI) / 180) +
          Math.abs(this.gravity) * this.mass) /
        Math.sin((frictionForce.directionInDegrees * Math.PI) / 180);
    }
    const frictionForceComponent: IForce = {
      description: "Static Friction Force",
      magnitude:
        coefficient * Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
      directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI,
      component: true,
    };
    const normalForceComponent: IForce = {
      description: "Normal Force",
      magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)),
      directionInDegrees:
        180 - 90 - (Math.atan(height / width) * 180) / Math.PI,
      component: true,
    };
    const gravityParallel: IForce = {
      description: "Gravity Parallel Component",
      magnitude:
      this.mass *
        Math.abs(this.gravity) *
        Math.sin(Math.PI / 2 - Math.atan(height / width)),
      directionInDegrees:
        180 - 90 - (Math.atan(height / width) * 180) / Math.PI + 180,
      component: true,
    };
    const gravityPerpendicular: IForce = {
      description: "Gravity Perpendicular Component",
      magnitude:
      this.mass *
        Math.abs(this.gravity) *
        Math.cos(Math.PI / 2 - Math.atan(height / width)),
      directionInDegrees: 360 - (Math.atan(height / width) * 180) / Math.PI,
      component: true,
    };
    const gravityForce: IForce = {
      description: "Gravity",
      magnitude: this.mass * Math.abs(this.gravity),
      directionInDegrees: 270,
      component: false,
    };
    if (coefficient != 0) {
      this.dataDoc.startForces = [gravityForce, normalForce, frictionForce];
      this.dataDoc.updatedForces = [gravityForce, normalForce, frictionForce];
      this.dataDoc.componentForces = [
        frictionForceComponent,
        normalForceComponent,
        gravityParallel,
        gravityPerpendicular,
      ];
    } else {
      this.dataDoc.startForces = [gravityForce, normalForce];
      this.dataDoc.updatedForces = [gravityForce, normalForce];
      this.dataDoc.componentForces = [
        normalForceComponent,
        gravityParallel,
        gravityPerpendicular,
      ];
    }
  };

  // Change wedge height and width and weight position to match new wedge angle
  changeWedgeBasedOnNewAngle = (angle: number) => {
    let width = 0;
    let height = 0;
    if (angle < 50) {
      width = 400;
      height = Math.tan((angle * Math.PI) / 180) * 400;
      this.dataDoc.wedgeWidth = width;
      this.dataDoc.wedgeHeight = height;
    } else if (angle < 70) {
      width = 200;
      height = Math.tan((angle * Math.PI) / 180) * 200;
      this.dataDoc.wedgeWidth = width;
      this.dataDoc.wedgeHeight = height;
    } else {
      width = 100;
      height = Math.tan((angle * Math.PI) / 180) * 100;
      this.dataDoc.wedgeWidth = width;
      this.dataDoc.wedgeHeight = height;
    }

    // update weight position based on updated wedge width/height
    let yPos = (width - this.radius) * Math.tan((angle * Math.PI) / 180);
    if (angle < 40) {
      yPos += Math.sqrt(angle);
    } else if (angle < 58) {
      yPos += angle / 2;
    } else if (angle < 68) {
      yPos += angle;
    } else if (angle < 70) {
      yPos += angle * 1.3;
    } else if (angle < 75) {
      yPos += angle * 1.5;
    } else if (angle < 78) {
      yPos += angle * 2;
    } else if (angle < 79) {
      yPos += angle * 2.25;
    } else if (angle < 80) {
      yPos += angle * 2.6;
    } else {
      yPos += angle * 3;
    }

    this.dataDoc.startPosX = Math.round((this.xMax * 0.5 - 200) * 10) / 10;
    this.dataDoc.startPosY = this.getDisplayYPos(yPos);
    if (this.dataDoc.mode == "Freeform") {
      this.updateForcesWithFriction(
        Number(this.dataDoc.coefficientOfStaticFriction),
        width,
        height
      );
    }
  };

  // In review mode, update forces when coefficient of static friction changed
  updateReviewForcesBasedOnCoefficient = (coefficient: number) => {
    let theta: number = Number(this.dataDoc.wedgeAngle);
    let index =
      this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45");
    if (index >= 0) {
      theta = this.dataDoc.questionVariables[index];
    }
    if (isNaN(theta)) {
      return;
    }
    this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
    this.dataDoc.reviewGravityAngle = (270);
    this.dataDoc.reviewNormalMagnitude = (
      Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)
    );
    this.dataDoc.reviewNormalAngle = (90 - theta);
    let yForce = -Math.abs(this.dataDoc.gravity);
    yForce +=
      Math.abs(this.dataDoc.gravity) *
      Math.cos((theta * Math.PI) / 180) *
      Math.sin(((90 - theta) * Math.PI) / 180);
    yForce +=
      coefficient *
      Math.abs(this.dataDoc.gravity) *
      Math.cos((theta * Math.PI) / 180) *
      Math.sin(((180 - theta) * Math.PI) / 180);
    let friction =
      coefficient * Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180);
    if (yForce > 0) {
      friction =
        (-(Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)) *
          Math.sin(((90 - theta) * Math.PI) / 180) +
          Math.abs(this.dataDoc.gravity)) /
        Math.sin(((180 - theta) * Math.PI) / 180);
    }
    this.dataDoc.reviewStaticMagnitude = (friction);
    this.dataDoc.reviewStaticAngle = (180 - theta);
  };

  // In review mode, update forces when wedge angle changed
  updateReviewForcesBasedOnAngle = (angle: number) => {
    this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity));
    this.dataDoc.reviewGravityAngle = (270);
    this.dataDoc.reviewNormalMagnitude = (
      Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)
    );
    this.dataDoc.reviewNormalAngle = (90 - angle);
    let yForce = -Math.abs(this.dataDoc.gravity);
    yForce +=
      Math.abs(this.dataDoc.gravity) *
      Math.cos((Number(angle) * Math.PI) / 180) *
      Math.sin(((90 - Number(angle)) * Math.PI) / 180);
    yForce +=
      this.dataDoc.reviewCoefficient *
      Math.abs(this.dataDoc.gravity) *
      Math.cos((Number(angle) * Math.PI) / 180) *
      Math.sin(((180 - Number(angle)) * Math.PI) / 180);
    let friction =
      this.dataDoc.reviewCoefficient *
      Math.abs(this.dataDoc.gravity) *
      Math.cos((Number(angle) * Math.PI) / 180);
    if (yForce > 0) {
      friction =
        (-(Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)) *
          Math.sin(((90 - Number(angle)) * Math.PI) / 180) +
          Math.abs(this.dataDoc.gravity)) /
        Math.sin(((180 - Number(angle)) * Math.PI) / 180);
    }
    this.dataDoc.reviewStaticMagnitude = (friction);
    this.dataDoc.reviewStaticAngle = (180 - angle);
  };

  // Solve for the correct answers to the generated problem
  getAnswersToQuestion = (
    question: QuestionTemplate,
    questionVars: number[]
  ) => {
    const solutions: number[] = [];

    let theta: number = Number(this.dataDoc.wedgeAngle);
    let index = question.variablesForQuestionSetup.indexOf("theta - max 45");
    if (index >= 0) {
      theta = questionVars[index];
    }
    let muS: number = Number(this.dataDoc.coefficientOfStaticFriction);
    index = question.variablesForQuestionSetup.indexOf(
      "coefficient of static friction"
    );
    if (index >= 0) {
      muS = questionVars[index];
    }

    for (let i = 0; i < question.answerSolutionDescriptions.length; i++) {
      const description = question.answerSolutionDescriptions[i];
      if (!isNaN(Number(description))) {
        solutions.push(Number(description));
      } else if (description == "solve normal force angle from wedge angle") {
        solutions.push(90 - theta);
      } else if (
        description == "solve normal force magnitude from wedge angle"
      ) {
        solutions.push(Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI));
      } else if (
        description ==
        "solve static force magnitude from wedge angle given equilibrium"
      ) {
        let normalForceMagnitude =
          Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI);
        let normalForceAngle = 90 - theta;
        let frictionForceAngle = 180 - theta;
        let frictionForceMagnitude =
          (-normalForceMagnitude *
            Math.sin((normalForceAngle * Math.PI) / 180) +
            Math.abs(this.dataDoc.gravity)) /
          Math.sin((frictionForceAngle * Math.PI) / 180);
        solutions.push(frictionForceMagnitude);
      } else if (
        description ==
        "solve static force angle from wedge angle given equilibrium"
      ) {
        solutions.push(180 - theta);
      } else if (
        description ==
        "solve minimum static coefficient from wedge angle given equilibrium"
      ) {
        let normalForceMagnitude =
          Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI);
        let normalForceAngle = 90 - theta;
        let frictionForceAngle = 180 - theta;
        let frictionForceMagnitude =
          (-normalForceMagnitude *
            Math.sin((normalForceAngle * Math.PI) / 180) +
            Math.abs(this.dataDoc.gravity)) /
          Math.sin((frictionForceAngle * Math.PI) / 180);
        let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude;
        solutions.push(frictionCoefficient);
      } else if (
        description ==
        "solve maximum wedge angle from coefficient of static friction given equilibrium"
      ) {
        solutions.push((Math.atan(muS) * 180) / Math.PI);
      }
    }
    this.dataDoc.selectedSolutions = (solutions);
    return solutions;
  };

  // In review mode, check if input answers match correct answers and optionally generate alert
  checkAnswers = (showAlert: boolean = true) => {
    let error: boolean = false;
    let epsilon: number = 0.01;
    if (this.dataDoc.selectedQuestion) {
      for (let i = 0; i < this.dataDoc.selectedQuestion.answerParts.length; i++) {
        if (this.dataDoc.selectedQuestion.answerParts[i] == "force of gravity") {
          if (
            Math.abs(this.dataDoc.reviewGravityMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
          ) {
            error = true;
          }
        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of gravity") {
          if (Math.abs(this.dataDoc.reviewGravityAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
            error = true;
          }
        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "normal force") {
          if (
            Math.abs(this.dataDoc.reviewNormalMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
          ) {
            error = true;
          }
        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of normal force") {
          if (Math.abs(this.dataDoc.reviewNormalAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
            error = true;
          }
        } else if (
          this.dataDoc.selectedQuestion.answerParts[i] == "force of static friction"
        ) {
          if (
            Math.abs(this.dataDoc.reviewStaticMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon
          ) {
            error = true;
          }
        } else if (
          this.dataDoc.selectedQuestion.answerParts[i] == "angle of static friction"
        ) {
          if (Math.abs(this.dataDoc.reviewStaticAngle - this.dataDoc.selectedSolutions[i]) > epsilon) {
            error = true;
          }
        } else if (
          this.dataDoc.selectedQuestion.answerParts[i] == "coefficient of static friction"
        ) {
          if (
            Math.abs(
              Number(this.dataDoc.coefficientOfStaticFriction) - this.dataDoc.selectedSolutions[i]
            ) > epsilon
          ) {
            error = true;
          }
        } else if (this.dataDoc.selectedQuestion.answerParts[i] == "wedge angle") {
          if (Math.abs(Number(this.dataDoc.wedgeAngle) - this.dataDoc.selectedSolutions[i]) > epsilon) {
            error = true;
          }
        }
      }
    }
    if (showAlert) {
      if (!error) {
        this.dataDoc.simulationPaused = (false);
        setTimeout(() => {
          this.dataDoc.simulationPaused = (true);
        }, 3000);
      } else {
        this.dataDoc.simulationPaused = (false);
        setTimeout(() => {
          this.dataDoc.simulationPaused = (true);
        }, 3000);
      }
    }
    if (this.dataDoc.selectedQuestion.goal == "noMovement") {
      if (!error) {
        this.dataDoc.noMovement = (true);
      } else {
        this.dataDoc.roMovement = (false);
      }
    }
  };

  // Reset all review values to default
  resetReviewValuesToDefault = () => {
    this.dataDoc.reviewGravityMagnitude = (0);
    this.dataDoc.reviewGravityAngle = (0);
    this.dataDoc.reviewNormalMagnitude = (0);
    this.dataDoc.reviewNormalAngle = (0);
    this.dataDoc.reviewStaticMagnitude = (0);
    this.dataDoc.reviewStaticAngle = (0);
    this.dataDoc.coefficientOfKineticFriction = (0);
    this.dataDoc.simulationPaused = (true);
    this.dataDoc.answerInputFields = (<div></div>);
  };

  // In review mode, reset problem variables and generate a new question
  generateNewQuestion = () => {
    this.resetReviewValuesToDefault();

    const vars: number[] = [];
    let question: QuestionTemplate = questions.inclinePlane[0];

    if (this.dataDoc.simulationType == "Inclined Plane") {
      if (this.dataDoc.questionNumber == questions.inclinePlane.length - 1) {
        this.dataDoc.questionNumber = (0);
      } else {
        this.dataDoc.questionNumber =(questionNumber + 1);
      }
      question = questions.inclinePlane[this.dataDoc.questionNumber];

      let coefficient = 0;
      let wedgeAngle = 0;

      for (let i = 0; i < question.variablesForQuestionSetup.length; i++) {
        if (question.variablesForQuestionSetup[i] == "theta - max 45") {
          let randValue = Math.floor(Math.random() * 44 + 1);
          vars.push(randValue);
          wedgeAngle = randValue;
        } else if (
          question.variablesForQuestionSetup[i] ==
          "coefficient of static friction"
        ) {
          let randValue = Math.round(Math.random() * 1000) / 1000;
          vars.push(randValue);
          coefficient = randValue;
        }
      }
      this.dataDoc.wedgeAngle = (wedgeAngle);
      this.changeWedgeBasedOnNewAngle(wedgeAngle);
      this.dataDoc.coefficientOfStaticFriction = (coefficient);
      this.dataDoc.reviewCoefficient = coefficient;
    }
    let q = "";
    for (let i = 0; i < question.questionSetup.length; i++) {
      q += question.questionSetup[i];
      if (i != question.questionSetup.length - 1) {
        q += vars[i];
        if (question.variablesForQuestionSetup[i].includes("theta")) {
          q +=
            " degree (≈" +
            Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 +
            " rad)";
        }
      }
    }
    this.dataDoc.questionVariables = vars;
    this.dataDoc.selectedQuestion = (question);
    this.dataDoc.questionPartOne = (q);
    this.dataDoc.questionPartTwo = (question.question);
    const answers = this.getAnswersToQuestion(question, vars);
    this.generateInputFieldsForQuestion(false, question, answers);
    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
  };

  // Generate answerInputFields for new review question
  generateInputFieldsForQuestion = (
    showIcon: boolean = false,
    question: QuestionTemplate = this.dataDoc.selectedQuestion,
    answers: number[] = this.dataDoc.selectedSolutions
  ) => {
    let answerInput = [];
    const d = new Date();
    for (let i = 0; i < question.answerParts.length; i++) {
      if (question.answerParts[i] == "force of gravity") {
        this.dataDoc.reviewGravityMagnitude = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Gravity magnitude</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewGravityMagnitude}
              step={0.1}
              unit={"N"}
              upperBound={50}
              value={this.dataDoc.reviewGravityMagnitude}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "angle of gravity") {
        this.dataDoc.reviewGravityAngle = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Gravity angle</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewGravityAngle}
              step={1}
              unit={"°"}
              upperBound={360}
              value={this.dataDoc.reviewGravityAngle}
              radianEquivalent={true}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "normal force") {
        this.dataDoc.reviewNormalMagnitude = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Normal force magnitude</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewNormalMagnitude}
              step={0.1}
              unit={"N"}
              upperBound={50}
              value={this.dataDoc.reviewNormalMagnitude}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "angle of normal force") {
        this.dataDoc.reviewNormalAngle = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Normal force angle</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewNormalAngle}
              step={1}
              unit={"°"}
              upperBound={360}
              value={this.dataDoc.reviewNormalAngle}
              radianEquivalent={true}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "force of static friction") {
        this.dataDoc.reviewStaticMagnitude = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Static friction magnitude</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewStaticMagnitude}
              step={0.1}
              unit={"N"}
              upperBound={50}
              value={this.dataDoc.reviewStaticMagnitude}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "angle of static friction") {
        this.dataDoc.reviewStaticAngle = (0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<p>Static friction angle</p>}
              lowerBound={0}
              changeValue={this.dataDoc.reviewStaticAngle}
              step={1}
              unit={"°"}
              upperBound={360}
              value={this.dataDoc.reviewStaticAngle}
              radianEquivalent={true}
              showIcon={showIcon}
              correctValue={answers[i]}
              labelWidth={"7em"}
            />
          </div>
        );
      } else if (question.answerParts[i] == "coefficient of static friction") {
        this.updateReviewForcesBasedOnCoefficient(0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={
                <Box>
                  &mu;<sub>s</sub>
                </Box>
              }
              lowerBound={0}
              changeValue={this.dataDoc.coefficientOfStaticFriction}
              step={0.1}
              unit={""}
              upperBound={1}
              value={this.dataDoc.coefficientOfStaticFriction}
              effect={this.updateReviewForcesBasedOnCoefficient}
              showIcon={showIcon}
              correctValue={answers[i]}
            />
          </div>
        );
      } else if (question.answerParts[i] == "wedge angle") {
        this.updateReviewForcesBasedOnAngle(0);
        answerInput.push(
          <div key={i + d.getTime()}>
            <InputField
              label={<Box>&theta;</Box>}
              lowerBound={0}
              changeValue={this.dataDoc.qedgeAngle}
              step={1}
              unit={"°"}
              upperBound={49}
              value={this.dataDoc.wedgeAngle}
              effect={(val: number) => {
                this.changeWedgeBasedOnNewAngle(val);
                this.updateReviewForcesBasedOnAngle(val);
              }}
              radianEquivalent={true}
              showIcon={showIcon}
              correctValue={answers[i]}
            />
          </div>
        );
      }
    }

    this.dataDoc.answerInputFields = (
      <div
        style={{ display: "flex", flexDirection: "column", alignItems: "left" }}
      >
        {answerInput}
      </div>
    );
  };
  
  // Default setup for uniform circular motion simulation
  setupCircular = (value: number) => {
    this.dataDoc.showComponentForces = (false);
    this.dataDoc.startVelY = (0);
    this.dataDoc.startVelX = (value);
    let xPos = (this.xMax + this.xMin) / 2 - this.radius;
    let yPos = (this.yMax + this.yMin) / 2 + this.dataDoc.circularMotionRadius - this.radius;
    this.dataDoc.startPosY = (yPos);
    this.dataDoc.startPosX = (xPos);
    const tensionForce: IForce = {
      description: "Centripetal Force",
      magnitude: (this.dataDoc.startVelX ** 2 * this.dataDoc.mass) / this.dataDoc.circularMotionRadius,
      directionInDegrees: 90,
      component: false,
    };
    this.dataDoc.updatedForces = ([tensionForce]);
    this.dataDoc.startForces = ([tensionForce]);
    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
  };

  // Default setup for pendulum simulation
  setupPendulum = () => {
    const length = 300;
    const angle = 30;
    const x = length * Math.cos(((90 - angle) * Math.PI) / 180);
    const y = length * Math.sin(((90 - angle) * Math.PI) / 180);
    const xPos = this.xMax / 2 - x - this.radius;
    const yPos = y - this.radius - 5;
    this.dataDoc.startPosX = (xPos);
    this.dataDoc.startPosY = (yPos);
    const mag = this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin((60 * Math.PI) / 180);
    const forceOfTension: IForce = {
      description: "Tension",
      magnitude: mag,
      directionInDegrees: 90 - angle,
      component: false,
    };

    const tensionComponent: IForce = {
      description: "Tension",
      magnitude: mag,
      directionInDegrees: 90 - angle,
      component: true,
    };
    const gravityParallel: IForce = {
      description: "Gravity Parallel Component",
      magnitude:
      this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin(((90 - angle) * Math.PI) / 180),
      directionInDegrees: -angle - 90,
      component: true,
    };
    const gravityPerpendicular: IForce = {
      description: "Gravity Perpendicular Component",
      magnitude:
      this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.cos(((90 - angle) * Math.PI) / 180),
      directionInDegrees: -angle,
      component: true,
    };

    this.dataDoc.componentForces = ([
      tensionComponent,
      gravityParallel,
      gravityPerpendicular,
    ]);
    this.dataDoc.updatedForces = ([
      {
        description: "Gravity",
        magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
        directionInDegrees: 270,
        component: false,
      },
      forceOfTension,
    ]);
    this.dataDoc.startForces = ([
      {
        description: "Gravity",
        magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
        directionInDegrees: 270,
        component: false,
      },
      forceOfTension,
    ]);
    this.dataDoc.startPendulumAngle = (30);
    this.dataDoc.pendulumAngle = (30);
    this.dataDoc.pendulumLength = (300);
    this.dataDoc.adjustPendulumAngle = ({ angle: 30, length: 300 });
  };

  // Default setup for spring simulation
  setupSpring = () => {
    this.dataDoc.showComponentForces = (false);
    const gravityForce: IForce = {
      description: "Gravity",
      magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
      directionInDegrees: 270,
      component: false,
    };
    this.dataDoc.updatedForces = ([gravityForce]);
    this.dataDoc.startForces = ([gravityForce]);
    this.dataDoc.startPosX = (this.xMax / 2 - this.radius);
    this.dataDoc.startPosY = (200);
    this.dataDoc.springConstant = (0.5);
    this.dataDoc.springRestLength = (200);
    this.dataDoc.springStartLength = (200);
    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
  };

  // Default setup for suspension simulation
  setupSuspension = () => {
    let xPos = (this.xMax + this.xMin) / 2 - this.radius;
    let yPos = this.yMin + 200;
    this.dataDoc.startPosY = (yPos);
    this.dataDoc.startPosX = (xPos);
    this.dataDoc.positionYDisplay = (getDisplayYPos(yPos));
    this.dataDoc.positionXDisplay = (xPos);
    let tensionMag = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / (2 * Math.sin(Math.PI / 4));
    const tensionForce1: IForce = {
      description: "Tension",
      magnitude: tensionMag,
      directionInDegrees: 45,
      component: false,
    };
    const tensionForce2: IForce = {
      description: "Tension",
      magnitude: tensionMag,
      directionInDegrees: 135,
      component: false,
    };
    const grav: IForce = {
      description: "Gravity",
      magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
      directionInDegrees: 270,
      component: false,
    };
    this.dataDoc.updatedForces = ([tensionForce1, tensionForce2, grav]);
    this.dataDoc.startForces = ([tensionForce1, tensionForce2, grav]);
    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
  };

  // Default setup for pulley simulation
  setupPulley = () => {
    this.dataDoc.showComponentForces = (false);
    this.dataDoc.startPosY = ((this.yMax + this.yMin) / 2);
    this.dataDoc.startPosX = ((this.xMin + this.xMax) / 2 - 105);
    this.dataDoc.positionYDisplay = (getDisplayYPos((this.yMax + this.yMin) / 2));
    this.dataDoc.positionXDisplay = ((this.xMin + this.xMax) / 2 - 105);
    let a = (-1 * ((mass - mass2) * Math.abs(gravity))) / (mass + mass2);
    const gravityForce1: IForce = {
      description: "Gravity",
      magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
      directionInDegrees: 270,
      component: false,
    };
    const tensionForce1: IForce = {
      description: "Tension",
      magnitude: this.dataDoc.mass * a + this.dataDoc.mass * Math.abs(this.dataDoc.gravity),
      directionInDegrees: 90,
      component: false,
    };
    a *= -1;
    const gravityForce2: IForce = {
      description: "Gravity",
      magnitude: this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
      directionInDegrees: 270,
      component: false,
    };
    const tensionForce2: IForce = {
      description: "Tension",
      magnitude: this.dataDoc.mass2 * a + this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity),
      directionInDegrees: 90,
      component: false,
    };
    this.dataDoc.updatedForces = ([gravityForce1, tensionForce1]);
    this.dataDoc.startForces = ([gravityForce1, tensionForce1]);
    this.dataDoc.startPosY2 = ((yMax + yMin) / 2);
    this.dataDoc.startPosX2 = ((xMin + xMax) / 2 + 5);
    this.dataDoc.positionYDisplay2 = (getDisplayYPos((yMax + yMin) / 2));
    this.dataDoc.positionXDisplay2 = ((xMin + xMax) / 2 + 5);
    this.dataDoc.updatedForces2 = ([gravityForce2, tensionForce2]);
    this.dataDoc.startForces2 = ([gravityForce2, tensionForce2]);
    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
  };

  // Helper function used for tutorial and review mode
  getForceFromJSON = (
    json: {
      description: string;
      magnitude: number;
      directionInDegrees: number;
      component: boolean;
    }[]
  ): IForce[] => {
    const forces: IForce[] = [];
    for (let i = 0; i < json.length; i++) {
      const force: IForce = {
        description: json[i].description,
        magnitude: json[i].magnitude,
        directionInDegrees: json[i].directionInDegrees,
        component: json[i].component,
      };
      forces.push(force);
    }
    return forces;
  };

  // Handle force change in review mode
  updateReviewModeValues = () => {
    const forceOfGravityReview: IForce = {
      description: "Gravity",
      magnitude: this.dataDoc.reviewGravityMagnitude,
      directionInDegrees: this.dataDoc.reviewGravityAngle,
      component: false,
    };
    const normalForceReview: IForce = {
      description: "Normal Force",
      magnitude: this.dataDoc.reviewNormalMagnitude,
      directionInDegrees: this.dataDoc.reviewNormalAngle,
      component: false,
    };
    const staticFrictionForceReview: IForce = {
      description: "Static Friction Force",
      magnitude: this.dataDoc.reviewStaticMagnitude,
      directionInDegrees: this.dataDoc.reviewStaticAngle,
      component: false,
    };
    this.dataDoc.startForces = ([
      forceOfGravityReview,
      normalForceReview,
      staticFrictionForceReview,
    ]);
    this.dataDoc.updatedForces = ([
      forceOfGravityReview,
      normalForceReview,
      staticFrictionForceReview,
    ]);
  }

  render () { 
    <div className="physicsSimApp">
    <div className="mechanicsSimulationContainer">
      <div
        className="mechanicsSimulationContentContainer"
      >
        <div className="mechanicsSimulationButtonsAndElements">
          <div className="mechanicsSimulationButtons">
            {!this.dataDoc.simulationPaused && (
              <div
                style={{
                  position: "fixed",
                  left: "10vw",
                  top: "95vh",
                  width: "50vw",
                }}
              >
                <LinearProgress />
              </div>
            )}
            <div
              style={{
                position: "fixed",
                top: 1 + "em",
                left: xMin + 12 + "px",
              }}
            >
              <div className="dropdownMenu">
                <select
                  value={this.dataDoc.simulationType}
                  onChange={(event) => {
                    this.dataDoc.simulationType = (event.target.value);
                    // TODO change simulation type based on mode/type
                  }}
                  style={{ height: "2em", width: "100%", fontSize: "16px" }}
                >
                  <option value="One Weight">Projectile</option>
                  <option value="Inclined Plane">Inclined Plane</option>
                  <option value="Pendulum">Pendulum</option>
                  <option value="Spring">Spring</option>
                  <option value="Circular Motion">Circular Motion</option>
                  <option value="Pulley">Pulley</option>
                  <option value="Suspension">Suspension</option>
                </select>
              </div>
            </div>
          </div>
          <div className="mechanicsSimulationElements">
            <Weight
              dataDoc={this.dataDoc}
              adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
              gravity={this.dataDoc.gravity}
              circularMotionRadius={this.dataDoc.circularMotionRadius}
              componentForces={this.dataDoc.componentForces}
              showComponentForces={this.dataDoc.showComponentForces}
              color={"red"}
              coefficientOfKineticFriction={Number(
                this.dataDoc.coefficientOfKineticFriction
              )}
              displayXVelocity={this.dataDoc.velocityXDisplay}
              displayYVelocity={this.dataDoc.velocityYDisplay}
              elasticCollisions={this.dataDoc.elasticCollisions}
              mass={this.dataDoc.mass}
              mode={this.dataDoc.mode}
              noMovement={this.dataDoc.noMovement}
              paused={this.dataDoc.simulationPaused}
              pendulumAngle={this.dataDoc.pendulumAngle}
              pendulumLength={this.dataDoc.pendulumLength}
              radius={this.radius}
              reset={this.dataDoc.simulationReset}
              simulationSpeed={this.dataDoc.simulationSpeed}
              startPendulumAngle={this.dataDoc.startPendulumAngle}
              showAcceleration={this.dataDoc.showAcceleration}
              showForceMagnitudes={this.dataDoc.showForceMagnitudes}
              showForces={this.dataDoc.showForces}
              showVelocity={this.dataDoc.showVelocity}
              simulationType={this.dataDoc.simulationType}
              springConstant={this.dataDoc.springConstant}
              springStartLength={this.dataDoc.springStartLength}
              springRestLength={this.dataDoc.springRestLength}
              startForces={this.dataDoc.startForces}
              startPosX={this.dataDoc.startPosX}
              startPosY={this.dataDoc.startPosY}
              startVelX={this.dataDoc.startVelX}
              startVelY={this.dataDoc.startVelY}
              timestepSize={0.05}
              updateDisplay={this.dataDoc.displayChange}
              updatedForces={this.dataDoc.updatedForces}
              wedgeHeight={this.dataDoc.wedgeHeight}
              wedgeWidth={this.dataDoc.wedgeWidth}
              xMax={this.xMax}
              xMin={this.xMin}
              yMax={this.yMax}
              yMin={this.yMin}
            />
            {this.dataDoc.simulationType == "Pulley" && (
              <Weight
                dataDoc={this.dataDoc}
                adjustPendulumAngle={this.dataDoc.adjustPendulumAngle}
                circularMotionRadius={this.dataDoc.circularMotionRadius}
                gravity={this.dataDoc.gravity}
                componentForces={this.dataDoc.componentForces}
                showComponentForces={this.dataDoc.showComponentForces}
                color={"blue"}
                coefficientOfKineticFriction={Number(
                  this.dataDoc.coefficientOfKineticFriction
                )}
                displayXVelocity={this.dataDoc.velocityXDisplay2}
                displayYVelocity={this.dataDoc.velocityYDisplay2}
                elasticCollisions={this.dataDoc.elasticCollisions}
                mass={this.dataDoc.mass2}
                mode={this.dataDoc.mode}
                noMovement={this.dataDoc.noMovement}
                paused={this.dataDoc.simulationPaused}
                pendulumAngle={this.dataDoc.pendulumAngle}
                pendulumLength={this.dataDoc.pendulumLength}
                radius={this.dataDoc.radius}
                reset={this.dataDoc.simulationReset}
                simulationSpeed={this.dataDoc.simulationSpeed}
                startPendulumAngle={this.dataDoc.startPendulumAngle}
                showAcceleration={this.dataDoc.showAcceleration}
                showForceMagnitudes={this.dataDoc.showForceMagnitudes}
                showForces={this.dataDoc.showForces}
                showVelocity={this.dataDoc.showVelocity}
                simulationType={this.dataDoc.simulationType}
                springConstant={this.dataDoc.springConstant}
                springStartLength={this.dataDoc.springStartLength}
                springRestLength={this.dataDoc.springRestLength}
                startForces={this.dataDoc.startForces2}
                startPosX={this.dataDoc.startPosX2}
                startPosY={this.dataDoc.startPosY2}
                startVelX={this.dataDoc.startVelX}
                startVelY={this.dataDoc.startVelY}
                timestepSize={0.05}
                updateDisplay={this.dataDoc.displayChange2}
                updatedForces={this.dataDoc.updatedForces2}
                wedgeHeight={this.dataDoc.wedgeHeight}
                wedgeWidth={this.dataDoc.wedgeWidth}
                xMax={this.xMax}
                xMin={this.xMin}
                yMax={this.yMax}
                yMin={this.yMin}
              />
            )}
          </div>
          <div>
            {(this.dataDoc.simulationType == "One Weight" ||
              this.dataDoc.simulationType == "Inclined Plane") &&
              this.wallPositions.map((element, index) => {
                return (
                  <Wall
                    key={index}
                    length={element.length}
                    xPos={element.xPos}
                    yPos={element.yPos}
                    angleInDegrees={element.angleInDegrees}
                  />
                );
              })}
          </div>
        </div>
      </div>
      <div className="mechanicsSimulationEquationContainer">
        <div className="mechanicsSimulationControls">
          <Stack direction="row" spacing={1}>
            {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
              <IconButton
                onClick={() => {
                  this.dataDoc.simulationPaused = (false);
                }}
              >
                <PlayArrowIcon />
              </IconButton>
            )}
            {!this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
              <IconButton
                onClick={() => {
                  this.dataDoc.simulationPaused = (true);
                }}
              >
                <PauseIcon />
              </IconButton>
            )}
            {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && (
              <IconButton
                onClick={() => {
                  this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                }}
              >
                <ReplayIcon />
              </IconButton>
            )}
          </Stack>
          <div className="dropdownMenu">
            <select
              value={mode}
              onChange={(event) => {
                this.dataDoc.mode = (event.target.value);

                // TODO setup simulation based on type and mode
              }}
              style={{ height: "2em", width: "100%", fontSize: "16px" }}
            >
              <option value="Tutorial">Tutorial Mode</option>
              <option value="Freeform">Freeform Mode</option>
              <option value="Review">Review Mode</option>
            </select>
          </div>
        </div>
        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType != "Inclined Plane" && (
          <div className="wordProblemBox">
            <p>{this.dataDoc.simulationType} review problems in progress!</p>
          </div>
        )}
        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
          <div>
            {!this.dataDoc.hintDialogueOpen && (
              <IconButton
                onClick={() => {
                  this.dataDoc.hintDialogueOpen = (true);
                }}
                sx={{
                  position: "fixed",
                  left: xMax - 50 + "px",
                  top: yMin + 14 + "px",
                }}
              >
                <QuestionMarkIcon />
              </IconButton>
            )}
            <Dialog
              maxWidth={"sm"}
              fullWidth={true}
              open={this.dataDoc.hintDialogueOpen}
              onClose={() => this.dataDoc.hintDialogueOpen = (false)}
            >
              <DialogTitle>Hints</DialogTitle>
              <DialogContent>
                {this.dataDoc.selectedQuestion.hints.map((hint, index) => {
                  return (
                    <div key={index}>
                      <DialogContentText>
                        <details>
                          <summary>
                            <b>
                              Hint {index + 1}: {hint.description}
                            </b>
                          </summary>
                          {hint.content}
                        </details>
                      </DialogContentText>
                    </div>
                  );
                })}
              </DialogContent>
              <DialogActions>
                <Button
                  onClick={() => {
                    this.dataDoc.hintDialogueOpen = (false);
                  }}
                >
                  Close
                </Button>
              </DialogActions>
            </Dialog>
            <div className="wordProblemBox">
              <div className="question">
                <p>{this.dataDoc.questionPartOne}</p>
                <p>{this.dataDoc.questionPartTwo}</p>
              </div>
              <div className="answer">{this.dataDoc.answerInputFields}</div>
            </div>
          </div>
        )}
        {this.dataDoc.mode == "Tutorial" && (
          <div className="wordProblemBox">
            <div className="question">
              <h2>Problem</h2>
              <p>{this.dataDoc.selectedTutorial.question}</p>
            </div>
            <div
              style={{
                display: "flex",
                justifyContent: "spaceBetween",
                width: "100%",
              }}
            >
              <IconButton
                onClick={() => {
                  let step = this.dataDoc.stepNumber - 1;
                  step = Math.max(step, 0);
                  step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
                  this.dataDoc.stepNumber = (step);
                  this.dataDoc.startForces = (
                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
                  );
                  this.dataDoc.updatedForces = (
                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
                  );
                  this.dataDoc.showForceMagnitudes = (
                    this.dataDoc.selectedTutorial.steps[step].showMagnitude
                  );
                }}
                disabled={stepNumber == 0}
              >
                <ArrowLeftIcon />
              </IconButton>
              <div>
                <h3>
                  Step {this.dataDoc.stepNumber + 1}:{" "}
                  {this.dataDoc.selectedTutorial.steps[stepNumber].description}
                </h3>
                <p>{this.dataDoc.selectedTutorial.steps[stepNumber].content}</p>
              </div>
              <IconButton
                onClick={() => {
                  let step = this.dataDoc.stepNumber + 1;
                  step = Math.max(step, 0);
                  step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1);
                  this.dataDoc.stepNumber = (step);
                  this.dataDoc.startForces = (
                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
                  );
                  this.dataDoc.updatedForces = (
                    this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces)
                  );
                  this.dataDoc.showForceMagnitudes = (
                    this.dataDoc.selectedTutorial.steps[step].showMagnitude
                  );
                }}
                disabled={this.dataDoc.stepNumber == this.dataDoc.selectedTutorial.steps.length - 1}
              >
                <ArrowRightIcon />
              </IconButton>
            </div>
            <div>
              {(this.dataDoc.simulationType == "One Weight" ||
                this.dataDoc.simulationType == "Inclined Plane" ||
                this.dataDoc.simulationType == "Pendulum") && <p>Resources</p>}
              {this.dataDoc.simulationType == "One Weight" && (
                <ul>
                  <li>
                    <a
                      href="https://www.khanacademy.org/science/physics/one-dimensional-motion"
                      target="_blank"
                      rel="noreferrer"
                      style={{
                        color: "blue",
                        textDecoration: "underline",
                      }}
                    >
                      Khan Academy - One Dimensional Motion
                    </a>
                  </li>
                  <li>
                    <a
                      href="https://www.khanacademy.org/science/physics/two-dimensional-motion"
                      target="_blank"
                      rel="noreferrer"
                      style={{
                        color: "blue",
                        textDecoration: "underline",
                      }}
                    >
                      Khan Academy - Two Dimensional Motion
                    </a>
                  </li>
                </ul>
              )}
              {this.dataDoc.simulationType == "Inclined Plane" && (
                <ul>
                  <li>
                    <a
                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#normal-contact-force"
                      target="_blank"
                      rel="noreferrer"
                      style={{
                        color: "blue",
                        textDecoration: "underline",
                      }}
                    >
                      Khan Academy - Normal Force
                    </a>
                  </li>
                  <li>
                    <a
                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#inclined-planes-friction"
                      target="_blank"
                      rel="noreferrer"
                      style={{
                        color: "blue",
                        textDecoration: "underline",
                      }}
                    >
                      Khan Academy - Inclined Planes
                    </a>
                  </li>
                </ul>
              )}
              {this.dataDoc.simulationType == "Pendulum" && (
                <ul>
                  <li>
                    <a
                      href="https://www.khanacademy.org/science/physics/forces-newtons-laws#tension-tutorial"
                      target="_blank"
                      rel="noreferrer"
                      style={{
                        color: "blue",
                        textDecoration: "underline",
                      }}
                    >
                      Khan Academy - Tension
                    </a>
                  </li>
                </ul>
              )}
            </div>
          </div>
        )}
        {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && (
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              marginTop: "10px",
            }}
          >
            <p
              style={{
                color: "blue",
                textDecoration: "underline",
                cursor: "pointer",
              }}
              onClick={() => this.dataDoc.mode = ("Tutorial")}
            >
              {" "}
              Go to walkthrough{" "}
            </p>
            <div style={{ display: "flex", flexDirection: "column" }}>
              <Button
                onClick={() => {
                  this.dataDoc.simulationReset= (!this.dataDoc.simulationReset);
                  this.checkAnswers();
                  this.generateInputFieldsForQuestion(true);
                }}
                variant="outlined"
              >
                <p>Submit</p>
              </Button>
              <Button
                onClick={() => this.generateNewQuestion()}
                variant="outlined"
              >
                <p>New question</p>
              </Button>
            </div>
          </div>
        )}
        {this.dataDoc.mode == "Freeform" && (
          <div className="vars">
            <FormControl component="fieldset">
              <FormGroup>
                {this.dataDoc.simulationType == "One Weight" && (
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={this.dataDoc.elasticCollisions}
                        onChange={() =>
                          this.dataDoc.elasticCollisions= (!this.dataDoc.elasticCollisions)
                        }
                      />
                    }
                    label="Make collisions elastic"
                    labelPlacement="start"
                  />
                )}
                <FormControlLabel
                  control={
                    <Checkbox
                      checked={this.dataDoc.showForces}
                      onChange={() => this.dataDoc.showForces = (!this.dataDoc.showForces)}
                    />
                  }
                  label="Show force vectors"
                  labelPlacement="start"
                />
                {(this.dataDoc.simulationType == "Inclined Plane" ||
                  this.dataDoc.simulationType == "Pendulum") && (
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={this.dataDoc.showForces}
                        onChange={() =>
                          this.dataDoc.showComponentForces = (!this.dataDoc.showComponentForces)
                        }
                      />
                    }
                    label="Show component force vectors"
                    labelPlacement="start"
                  />
                )}
                <FormControlLabel
                  control={
                    <Checkbox
                      checked={this.dataDoc.showAcceleration}
                      onChange={() => this.dataDoc.showAcceleration = (!this.dataDoc.showAcceleration)}
                    />
                  }
                  label="Show acceleration vector"
                  labelPlacement="start"
                />
                <FormControlLabel
                  control={
                    <Checkbox
                      checked={this.dataDoc.showVelocity}
                      onChange={() => this.dataDoc.showVelocity = (!this.dataDoc.showVelocity)}
                    />
                  }
                  label="Show velocity vector"
                  labelPlacement="start"
                />
                <InputField
                  label={<Box>Speed</Box>}
                  lowerBound={1}
                  changeValue={this.dataDoc.simulationSpeed} //TODO - deal with input field change value now that datadoc is being used!
                  step={1}
                  unit={"x"}
                  upperBound={10}
                  value={this.dataDoc.simulationSpeed}
                  labelWidth={"5em"}
                />
                {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Circular Motion" && (
                  <InputField
                    label={<Box>Gravity</Box>}
                    lowerBound={-30}
                    changeValue={this.dataDoc.gravity}
                    step={0.01}
                    unit={"m/s2"}
                    upperBound={0}
                    value={this.dataDoc.gravity}
                    effect={(val: number) => {
                      this.dataDoc.resetAll = (!this.dataDoc.resetAll);
                    }}
                    labelWidth={"5em"}
                  />
                )}
                {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Pulley" && (
                  <InputField
                    label={<Box>Mass</Box>}
                    lowerBound={1}
                    changeValue={this.dataDoc.mass}
                    step={0.1}
                    unit={"kg"}
                    upperBound={5}
                    value={this.dataDoc.mass}
                    effect={(val: number) => {
                      this.dataDoc.resetAll = (!this.dataDoc.resetAll);
                    }}
                    labelWidth={"5em"}
                  />
                )}
                {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && (
                  <InputField
                    label={<Box>Red mass</Box>}
                    lowerBound={1}
                    changeValue={this.dataDoc.mass}
                    step={0.1}
                    unit={"kg"}
                    upperBound={5}
                    value={this.dataDoc.mass}
                    effect={(val: number) => {
                      this.dataDoc.resetAll = (!this.dataDoc.resetAll);
                    }}
                    labelWidth={"5em"}
                  />
                )}
                {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && (
                  <InputField
                    label={<Box>Blue mass</Box>}
                    lowerBound={1}
                    changeValue={this.dataDoc.mass2}
                    step={0.1}
                    unit={"kg"}
                    upperBound={5}
                    value={this.dataDoc.mass2}
                    effect={(val: number) => {
                      this.dataDoc.resetAll = (!this.dataDoc.resetAll);
                    }}
                    labelWidth={"5em"}
                  />
                )}
                {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Circular Motion" && (
                  <InputField
                    label={<Box>Rod length</Box>}
                    lowerBound={100}
                    changeValue={this.dataDoc.circularMotionRadius}
                    step={5}
                    unit={"kg"}
                    upperBound={250}
                    value={this.dataDoc.circularMotionRadius}
                    effect={(val: number) => {
                      this.dataDoc.resetAll = (!this.dataDoc.resetAll);
                    }}
                    labelWidth={"5em"}
                  />
                )}
              </FormGroup>
            </FormControl>
            {this.dataDoc.simulationType == "Spring" && this.dataDoc.simulationPaused && (
              <div>
                <InputField
                  label={
                    <Typography color="inherit">Spring stiffness</Typography>
                  }
                  lowerBound={0.1}
                  changeValue={this.dataDoc.springConstant}
                  step={1}
                  unit={"N/m"}
                  upperBound={500}
                  value={springConstant}
                  effect={(val: number) => {
                    this.dataDoc.simulationReset(!this.dataDoc.simulationReset);
                  }}
                  radianEquivalent={false}
                  mode={"Freeform"}
                  labelWidth={"7em"}
                />
                <InputField
                  label={<Typography color="inherit">Rest length</Typography>}
                  lowerBound={10}
                  changeValue={this.dataDoc.springRestLength}
                  step={100}
                  unit={""}
                  upperBound={500}
                  value={this.dataDoc.springRestLength}
                  effect={(val: number) => {
                    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                  }}
                  radianEquivalent={false}
                  mode={"Freeform"}
                  labelWidth={"7em"}
                />
                <InputField
                  label={
                    <Typography color="inherit">
                      Starting displacement
                    </Typography>
                  }
                  lowerBound={-(this.dataDoc.springRestLength - 10)}
                  changeValue={(val: number) => {}}
                  step={10}
                  unit={""}
                  upperBound={this.dataDoc.springRestLength}
                  value={this.dataDoc.springStartLength - this.dataDoc.springRestLength}
                  effect={(val: number) => {
                    this.dataDoc.startPosY = (this.dataDoc.springRestLength + val);
                    this.dataDoc.springStartLength = (this.dataDoc.springRestLength + val);
                    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                  }}
                  radianEquivalent={false}
                  mode={"Freeform"}
                  labelWidth={"7em"}
                />
              </div>
            )}
            {this.dataDoc.simulationType == "Inclined Plane" && this.dataDoc.simulationPaused && (
              <div>
                <InputField
                  label={<Box>&theta;</Box>}
                  lowerBound={0}
                  changeValue={this.dataDoc.wedgeAngle}
                  step={1}
                  unit={"°"}
                  upperBound={49}
                  value={this.dataDoc.wedgeAngle}
                  effect={(val: number) => {
                    this.changeWedgeBasedOnNewAngle(val);
                    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                  }}
                  radianEquivalent={true}
                  mode={"Freeform"}
                  labelWidth={"2em"}
                />
                <InputField
                  label={
                    <Box>
                      &mu;<sub>s</sub>
                    </Box>
                  }
                  lowerBound={0}
                  changeValue={this.dataDoc.coefficientOfStaticFriction}
                  step={0.1}
                  unit={""}
                  upperBound={1}
                  value={this.dataDoc.coefficientOfStaticFriction}
                  effect={(val: number) => {
                    this.updateForcesWithFriction(val);
                    if (val < Number(this.dataDoc.coefficientOfKineticFriction)) {
                      this.dataDoc.soefficientOfKineticFriction = (val);
                    }
                    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                  }}
                  mode={"Freeform"}
                  labelWidth={"2em"}
                />
                <InputField
                  label={
                    <Box>
                      &mu;<sub>k</sub>
                    </Box>
                  }
                  lowerBound={0}
                  changeValue={this.dataDoc.coefficientOfKineticFriction}
                  step={0.1}
                  unit={""}
                  upperBound={Number(this.dataDoc.coefficientOfStaticFriction)}
                  value={this.dataDoc.coefficientOfKineticFriction}
                  effect={(val: number) => {
                    this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                  }}
                  mode={"Freeform"}
                  labelWidth={"2em"}
                />
              </div>
            )}
            {this.dataDoc.simulationType == "Inclined Plane" && !this.dataDoc.simulationPaused && (
              <Typography>
                &theta;: {Math.round(Number(this.dataDoc.wedgeAngle) * 100) / 100}° ≈{" "}
                {Math.round(((Number(this.dataDoc.wedgeAngle) * Math.PI) / 180) * 100) /
                  100}{" "}
                rad
                <br />
                &mu; <sub>s</sub>: {this.dataDoc.coefficientOfStaticFriction}
                <br />
                &mu; <sub>k</sub>: {this.dataDoc.coefficientOfKineticFriction}
              </Typography>
            )}
            {this.dataDoc.simulationType == "Pendulum" && !this.dataDoc.simulationPaused && (
              <Typography>
                &theta;: {Math.round(this.dataDoc.pendulumAngle * 100) / 100}° ≈{" "}
                {Math.round(((this.dataDoc.pendulumAngle * Math.PI) / 180) * 100) / 100}{" "}
                rad
              </Typography>
            )}
            {this.dataDoc.simulationType == "Pendulum" && this.dataDoc.simulationPaused && (
              <div>
                <InputField
                  label={<Box>Angle</Box>}
                  lowerBound={0}
                  changeValue={this.dataDoc.pendulumAngle}
                  step={1}
                  unit={"°"}
                  upperBound={59}
                  value={this.dataDoc.pendulumAngle}
                  effect={(value) => {
                    this.dataDoc.startPendulumAngle = (value);
                    if (simulationType == "Pendulum") {
                      const mag =
                        mass *
                        Math.abs(this.dataDoc.gravity) *
                        Math.cos((value * Math.PI) / 180);

                      const forceOfTension: IForce = {
                        description: "Tension",
                        magnitude: mag,
                        directionInDegrees: 90 - value,
                        component: false,
                      };

                      const tensionComponent: IForce = {
                        description: "Tension",
                        magnitude: mag,
                        directionInDegrees: 90 - value,
                        component: true,
                      };
                      const gravityParallel: IForce = {
                        description: "Gravity Parallel Component",
                        magnitude:
                          Math.abs(this.dataDoc.gravity) *
                          Math.cos((value * Math.PI) / 180),
                        directionInDegrees: 270 - value,
                        component: true,
                      };
                      const gravityPerpendicular: IForce = {
                        description: "Gravity Perpendicular Component",
                        magnitude:
                          Math.abs(this.dataDoc.gravity) *
                          Math.sin((value * Math.PI) / 180),
                        directionInDegrees: -value,
                        component: true,
                      };

                      const length = this.dataDoc.pendulumLength;
                      const x =
                        length * Math.cos(((90 - value) * Math.PI) / 180);
                      const y =
                        length * Math.sin(((90 - value) * Math.PI) / 180);
                      const xPos = this.xMax / 2 - x - radius;
                      const yPos = y - radius - 5;
                      this.dataDoc.startPosX = (xPos);
                      this.dataDoc.startPosY= (yPos);

                      this.dataDoc.startForces = ([
                        {
                          description: "Gravity",
                          magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
                          directionInDegrees: 270,
                          component: false,
                        },
                        forceOfTension,
                      ]);
                      this.dataDoc.updatedForces = ([
                        {
                          description: "Gravity",
                          magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass,
                          directionInDegrees: 270,
                          component: false,
                        },
                        forceOfTension,
                      ]);
                      this.dataDoc.componentForces = ([
                        tensionComponent,
                        gravityParallel,
                        gravityPerpendicular,
                      ]);
                      this.dataDoc.adjustPendulumAngle = ({
                        angle: value,
                        length: pendulumLength,
                      });
                      this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                    }
                  }}
                  radianEquivalent={true}
                  mode={"Freeform"}
                  labelWidth={"5em"}
                />
                <InputField
                  label={<Box>Rod length</Box>}
                  lowerBound={0}
                  changeValue={this.dataDoc.pendulumLength}
                  step={1}
                  unit={"m"}
                  upperBound={400}
                  value={Math.round(this.dataDoc.pendulumLength)}
                  effect={(value) => {
                    if (simulationType == "Pendulum") {
                      this.dataDoc.adjustPendulumAngle = ({
                        angle: this.dataDoc.pendulumAngle,
                        length: value,
                      });
                      this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                    }
                  }}
                  radianEquivalent={false}
                  mode={"Freeform"}
                  labelWidth={"5em"}
                />
              </div>
            )}
          </div>
        )}
        <div className="mechanicsSimulationEquation">
          {this.dataDoc.mode == "Freeform" && (
            <table>
              <tbody>
                <tr>
                  <td>{this.dataDoc.simulationType == "Pulley" ? "Red Weight" : ""}</td>
                  <td>X</td>
                  <td>Y</td>
                </tr>
                <tr>
                  <td
                    style={{ cursor: "help" }}
                    // onClick={() => {
                    //   window.open(
                    //     "https://www.khanacademy.org/science/physics/two-dimensional-motion"
                    //   );
                    // }}
                  >
                    <Box>Position</Box>
                  </td>
                  {(!this.dataDoc.simulationPaused ||
                    this.dataDoc.simulationType == "Inclined Plane" ||
                    this.dataDoc.simulationType == "Suspension" ||
                    this.dataDoc.simulationType == "Circular Motion" ||
                    this.dataDoc.simulationType == "Pulley") && (
                    <td style={{ cursor: "default" }}>
                      {this.dataDoc.positionXDisplay} m
                    </td>
                  )}{" "}
                  {this.dataDoc.simulationPaused &&
                    this.dataDoc.simulationType != "Inclined Plane" &&
                    this.dataDoc.simulationType != "Suspension" &&
                    this.dataDoc.simulationType != "Circular Motion" &&
                    this.dataDoc.simulationType != "Pulley" && (
                      <td
                        style={{
                          cursor: "default",
                        }}
                      >
                        <InputField
                          lowerBound={0}
                          changeValue={this.dataDoc.positionXDisplay}
                          step={1}
                          unit={"m"}
                          upperBound={this.xMax - 110}
                          value={this.dataDoc.positionXDisplay}
                          effect={(value) => {
                            this.dataDoc.displayChange = ({
                              xDisplay: value,
                              yDisplay: this.dataDoc.positionYDisplay,
                            });
                          }}
                          small={true}
                          mode={"Freeform"}
                        />
                      </td>
                    )}{" "}
                  {(!this.dataDoc.simulationPaused ||
                    this.dataDoc.simulationType == "Inclined Plane" ||
                    this.dataDoc.simulationType == "Suspension" ||
                    this.dataDoc.simulationType == "Circular Motion" ||
                    this.dataDoc.simulationType == "Pulley") && (
                    <td style={{ cursor: "default" }}>
                      {this.dataDoc.positionYDisplay} m
                    </td>
                  )}{" "}
                  {this.dataDoc.simulationPaused &&
                    this.dataDoc.simulationType != "Inclined Plane" &&
                    this.dataDoc.simulationType != "Suspension" &&
                    this.dataDoc.simulationType != "Circular Motion" &&
                    this.dataDoc.simulationType != "Pulley" && (
                      <td
                        style={{
                          cursor: "default",
                        }}
                      >
                        <InputField
                          lowerBound={0}
                          changeValue={this.dataDoc.positionYDisplay}
                          step={1}
                          unit={"m"}
                          upperBound={this.yMax - 110}
                          value={this.dataDoc.positionYDisplay}
                          effect={(value) => {
                            this.dataDoc.displayChange = ({
                              xDisplay: this.dataDoc.positionXDisplay,
                              yDisplay: value,
                            });
                          }}
                          small={true}
                          mode={"Freeform"}
                        />
                      </td>
                    )}{" "}
                </tr>
                <tr>
                  <td
                    style={{ cursor: "help" }}
                    // onClick={() => {
                    //   window.open(
                    //     "https://www.khanacademy.org/science/physics/two-dimensional-motion"
                    //   );
                    // }}
                  >
                    <Box>Velocity</Box>
                  </td>
                  {(!this.dataDoc.simulationPaused ||
                    (this.dataDoc.simulationType != "One Weight" &&
                    this.dataDoc.simulationType != "Circular Motion")) && (
                    <td style={{ cursor: "default" }}>
                      {this.dataDoc.velocityXDisplay} m/s
                    </td>
                  )}{" "}
                  {this.dataDoc.simulationPaused &&
                    (this.dataDoc.simulationType == "One Weight" ||
                    this.dataDoc.simulationType == "Circular Motion") && (
                      <td
                        style={{
                          cursor: "default",
                        }}
                      >
                        <InputField
                          lowerBound={-50}
                          changeValue={this.dataDoc.velocityXDisplay}
                          step={1}
                          unit={"m/s"}
                          upperBound={50}
                          value={this.dataDoc.velocityXDisplay}
                          effect={(value) => {
                            this.dataDoc.startVelX = (value);
                            this.dataDoc.simulationReset = (!this.dataDoc.simulationReset);
                          }}
                          small={true}
                          mode={"Freeform"}
                        />
                      </td>
                    )}{" "}
                  {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType != "One Weight") && (
                    <td style={{ cursor: "default" }}>
                      {this.dataDoc.velocityYDisplay} m/s
                    </td>
                  )}{" "}
                  {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "One Weight" && (
                    <td
                      style={{
                        cursor: "default",
                      }}
                    >
                      <InputField
                        lowerBound={-50}
                        changeValue={this.dataDoc.velocityYDisplay}
                        step={1}
                        unit={"m/s"}
                        upperBound={50}
                        value={this.dataDoc.velocityYDisplay}
                        effect={(value) => {
                          this.dataDoc.startVelY = (-value);
                          this.dataDoc.displayChange = ({
                            xDisplay: this.dataDoc.positionXDisplay,
                            yDisplay: this.dataDoc.positionYDisplay,
                          });
                        }}
                        small={true}
                        mode={"Freeform"}
                      />
                    </td>
                  )}{" "}
                </tr>
                <tr>
                  <td
                    style={{ cursor: "help" }}
                    // onClick={() => {
                    //   window.open(
                    //     "https://www.khanacademy.org/science/physics/two-dimensional-motion"
                    //   );
                    // }}
                  >
                    <Box>Acceleration</Box>
                  </td>
                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.accelerationXDisplay} m/s<sup>2</sup>
                  </td>
                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.accelerationYDisplay} m/s<sup>2</sup>
                  </td>
                </tr>
                <tr>
                  <td>
                    <Box>Momentum</Box>
                  </td>
                  <td>
                    {Math.round(this.dataDoc.velocityXDisplay * this.dataDoc.mass * 10) / 10} kg*m/s
                  </td>
                  <td>
                    {Math.round(this.dataDoc.velocityYDisplay * this.dataDoc.mass * 10) / 10} kg*m/s
                  </td>
                </tr>
              </tbody>
            </table>
          )}
          {this.dataDoc.mode == "Freeform" && this.dataDoc.simulationType == "Pulley" && (
            <table>
              <tbody>
                <tr>
                  <td>Blue Weight</td>
                  <td>X</td>
                  <td>Y</td>
                </tr>
                <tr>
                  <td>
                    <Box>Position</Box>
                  </td>
                  <td style={{ cursor: "default" }}>{this.dataDoc.positionXDisplay2} m</td>
                  <td style={{ cursor: "default" }}>{this.dataDoc.positionYDisplay2} m</td>
                </tr>
                <tr>
                  <td>
                    <Box>Velocity</Box>
                  </td>
                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.velocityXDisplay2} m/s
                  </td>

                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.velocityYDisplay2} m/s
                  </td>
                </tr>
                <tr>
                  <td>
                    <Box>Acceleration</Box>
                  </td>
                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.accelerationXDisplay2} m/s<sup>2</sup>
                  </td>
                  <td style={{ cursor: "default" }}>
                    {this.dataDoc.accelerationYDisplay2} m/s<sup>2</sup>
                  </td>
                </tr>
                <tr>
                  <td>
                    <Box>Momentum</Box>
                  </td>
                  <td>
                    {Math.round(this.dataDoc.velocityXDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s
                  </td>
                  <td>
                    {Math.round(this.dataDoc.velocityYDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s
                  </td>
                </tr>
              </tbody>
            </table>
          )}
        </div>
        {this.dataDoc.simulationType != "Pendulum" && this.dataDoc.simulationType != "Spring" && (
          <div>
            <p>Kinematic Equations</p>
            <ul>
              <li>
                Position: x<sub>1</sub>=x<sub>0</sub>+v<sub>0</sub>t+
                <sup>1</sup>&frasl;
                <sub>2</sub>at
                <sup>2</sup>
              </li>
              <li>
                Velocity: v<sub>1</sub>=v<sub>0</sub>+at
              </li>
              <li>Acceleration: a = F/m</li>
            </ul>
          </div>
        )}
        {this.dataDoc.simulationType == "Spring" && (
          <div>
            <p>Harmonic Motion Equations: Spring</p>
            <ul>
              <li>
                Spring force: F<sub>s</sub>=kd
              </li>
              <li>
                Spring period: T<sub>s</sub>=2&pi;&#8730;<sup>m</sup>&frasl;
                <sub>k</sub>
              </li>
              <li>Equilibrium displacement for vertical spring: d = mg/k</li>
              <li>
                Elastic potential energy: U<sub>s</sub>=<sup>1</sup>&frasl;
                <sub>2</sub>kd<sup>2</sup>
              </li>
              <ul>
                <li>
                  Maximum when system is at maximum displacement, 0 when
                  system is at 0 displacement
                </li>
              </ul>
              <li>
                Translational kinetic energy: K=<sup>1</sup>&frasl;
                <sub>2</sub>mv<sup>2</sup>
              </li>
              <ul>
                <li>
                  Maximum when system is at maximum/minimum velocity (at 0
                  displacement), 0 when velocity is 0 (at maximum
                  displacement)
                </li>
              </ul>
            </ul>
          </div>
        )}
        {this.dataDoc.simulationType == "Pendulum" && (
          <div>
            <p>Harmonic Motion Equations: Pendulum</p>
            <ul>
              <li>
                Pendulum period: T<sub>p</sub>=2&pi;&#8730;<sup>l</sup>&frasl;
                <sub>g</sub>
              </li>
            </ul>
          </div>
        )}
      </div>
    </div>
    <div
      style={{
        position: "fixed",
        top: this.layoutDoc._height - 120 + 20 + "px",
        left: this.xMin + 90 - 80 + "px",
        zIndex: -10000,
      }}
    >
      <svg width={100 + "px"} height={100 + "px"}>
        <defs>
          <marker
            id="miniArrow"
            markerWidth="20"
            markerHeight="20"
            refX="0"
            refY="3"
            orient="auto"
            markerUnits="strokeWidth"
          >
            <path d="M0,0 L0,6 L9,3 z" fill={"#000000"} />
          </marker>
        </defs>
        <line
          x1={20}
          y1={70}
          x2={70}
          y2={70}
          stroke={"#000000"}
          strokeWidth="2"
          markerEnd="url(#miniArrow)"
        />
        <line
          x1={20}
          y1={70}
          x2={20}
          y2={20}
          stroke={"#000000"}
          strokeWidth="2"
          markerEnd="url(#miniArrow)"
        />
      </svg>
      <p
        style={{
          position: "fixed",
          top: this.layoutDoc._height - 120 + 40 + "px",
          left: this.xMin + 90 - 80 + "px",
        }}
      >
        {simulationType == "Circular Motion" ? "Z" : "Y"}
      </p>
      <p
        style={{
          position: "fixed",
          top: this.layoutDoc._height - 120 + 80 + "px",
          left: this.xMin + 90 - 40 + "px",
        }}
      >
        X
      </p>
    </div>
  </div>
  }