public void setMotorMount(MotorMount mount) {
   if (mount != null) {
     for (MotorConfiguration m : mount.getMotorConfiguration()) {
       this.usedMotors.add((ThrustCurveMotor) m.getMotor());
     }
   }
 }
  /**
   * Create a new motor instance configuration for the rocket configuration.
   *
   * @param configuration the rocket configuration.
   * @return a new motor instance configuration with all motors in place.
   */
  private MotorInstanceConfiguration setupMotorConfiguration(Configuration configuration) {
    MotorInstanceConfiguration motors = new MotorInstanceConfiguration();
    final String motorId = configuration.getMotorConfigurationID();

    Iterator<MotorMount> iterator = configuration.motorIterator();
    while (iterator.hasNext()) {
      MotorMount mount = iterator.next();
      RocketComponent component = (RocketComponent) mount;
      Motor motor = mount.getMotor(motorId);

      if (motor != null) {
        Coordinate[] positions = component.toAbsolute(mount.getMotorPosition(motorId));
        for (int i = 0; i < positions.length; i++) {
          Coordinate position = positions[i];
          MotorId id = new MotorId(component.getID(), i + 1);
          motors.addMotor(id, motor.getInstance(), mount, position);
        }
      }
    }
    return motors;
  }
  /**
   * Handles events occurring during the flight from the event queue. Each event that has occurred
   * before or at the current simulation time is processed. Suitable events are also added to the
   * flight data.
   */
  private boolean handleEvents() throws SimulationException {
    boolean ret = true;
    FlightEvent event;

    for (event = nextEvent(); event != null; event = nextEvent()) {

      // Ignore events for components that are no longer attached to the rocket
      if (event.getSource() != null
          && event.getSource().getParent() != null
          && !status.getConfiguration().isStageActive(event.getSource().getStageNumber())) {
        continue;
      }

      // Call simulation listeners, allow aborting event handling
      if (!SimulationListenerHelper.fireHandleFlightEvent(status, event)) {
        continue;
      }

      if (event.getType() != FlightEvent.Type.ALTITUDE) {
        log.verbose("BasicEventSimulationEngine:  Handling event " + event);
      }

      if (event.getType() == FlightEvent.Type.IGNITION) {
        MotorMount mount = (MotorMount) event.getSource();
        MotorId motorId = (MotorId) event.getData();
        MotorInstance instance = status.getMotorConfiguration().getMotorInstance(motorId);
        if (!SimulationListenerHelper.fireMotorIgnition(status, motorId, mount, instance)) {
          continue;
        }
      }

      if (event.getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) {
        RecoveryDevice device = (RecoveryDevice) event.getSource();
        if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(status, device)) {
          continue;
        }
      }

      // Check for motor ignition events, add ignition events to queue
      for (MotorId id : status.getMotorConfiguration().getMotorIDs()) {
        MotorMount mount = status.getMotorConfiguration().getMotorMount(id);
        RocketComponent component = (RocketComponent) mount;

        if (mount.getIgnitionEvent().isActivationEvent(event, component)) {
          addEvent(
              new FlightEvent(
                  FlightEvent.Type.IGNITION,
                  status.getSimulationTime() + mount.getIgnitionDelay(),
                  component,
                  id));
        }
      }

      // Check for stage separation event
      for (int stageNo : status.getConfiguration().getActiveStages()) {
        if (stageNo == 0) continue;

        Stage stage = (Stage) status.getConfiguration().getRocket().getChild(stageNo);
        if (stage.getSeparationEvent().isSeparationEvent(event, stage)) {
          addEvent(
              new FlightEvent(
                  FlightEvent.Type.STAGE_SEPARATION,
                  event.getTime() + stage.getSeparationDelay(),
                  stage));
        }
      }

      // Check for recovery device deployment, add events to queue
      Iterator<RocketComponent> rci = status.getConfiguration().iterator();
      while (rci.hasNext()) {
        RocketComponent c = rci.next();
        if (!(c instanceof RecoveryDevice)) continue;
        if (((RecoveryDevice) c).getDeployEvent().isActivationEvent(event, c)) {
          // Delay event by at least 1ms to allow stage separation to occur first
          addEvent(
              new FlightEvent(
                  FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT,
                  event.getTime() + Math.max(0.001, ((RecoveryDevice) c).getDeployDelay()),
                  c));
        }
      }

      // Handle event
      switch (event.getType()) {
        case LAUNCH:
          {
            status.getFlightData().addEvent(event);
            break;
          }

        case IGNITION:
          {
            // Ignite the motor
            MotorMount mount = (MotorMount) event.getSource();
            RocketComponent component = (RocketComponent) mount;
            MotorId motorId = (MotorId) event.getData();
            MotorInstanceConfiguration config = status.getMotorConfiguration();
            config.setMotorIgnitionTime(motorId, event.getTime());
            status.setMotorIgnited(true);
            status.getFlightData().addEvent(event);

            break;
          }

        case LIFTOFF:
          {
            // Mark lift-off as occurred
            status.setLiftoff(true);
            status.getFlightData().addEvent(event);
            break;
          }

        case LAUNCHROD:
          {
            // Mark launch rod as cleared
            status.setLaunchRodCleared(true);
            status.getFlightData().addEvent(event);
            break;
          }

        case BURNOUT:
          {
            // If motor burnout occurs without lift-off, abort
            if (!status.isLiftoff()) {
              throw new SimulationLaunchException("Motor burnout without liftoff.");
            }
            // Add ejection charge event
            String id = status.getConfiguration().getMotorConfigurationID();
            MotorMount mount = (MotorMount) event.getSource();
            double delay = mount.getMotorDelay(id);
            if (delay != Motor.PLUGGED) {
              addEvent(
                  new FlightEvent(
                      FlightEvent.Type.EJECTION_CHARGE,
                      status.getSimulationTime() + delay,
                      event.getSource(),
                      event.getData()));
            }
            status.getFlightData().addEvent(event);
            break;
          }

        case EJECTION_CHARGE:
          {
            status.getFlightData().addEvent(event);
            break;
          }

        case STAGE_SEPARATION:
          {
            // TODO: HIGH: Store lower stages to be simulated later
            RocketComponent stage = event.getSource();
            int n = stage.getStageNumber();
            status.getConfiguration().setToStage(n - 1);
            status.getFlightData().addEvent(event);
            break;
          }

        case APOGEE:
          // Mark apogee as reached
          status.setApogeeReached(true);
          status.getFlightData().addEvent(event);
          break;

        case RECOVERY_DEVICE_DEPLOYMENT:
          RocketComponent c = event.getSource();
          int n = c.getStageNumber();
          // Ignore event if stage not active
          if (status.getConfiguration().isStageActive(n)) {
            // TODO: HIGH: Check stage activeness for other events as well?

            // Check whether any motor in the active stages is active anymore
            for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
              int stage =
                  ((RocketComponent) status.getMotorConfiguration().getMotorMount(motorId))
                      .getStageNumber();
              if (!status.getConfiguration().isStageActive(stage)) continue;
              if (!status.getMotorConfiguration().getMotorInstance(motorId).isActive()) continue;
              status.getWarnings().add(Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING);
            }

            // Check for launch rod
            if (!status.isLaunchRodCleared()) {
              status
                  .getWarnings()
                  .add(
                      Warning.fromString(
                          "Recovery device device deployed while on " + "the launch guide."));
            }

            // Check current velocity
            if (status.getRocketVelocity().length() > 20) {
              // TODO: LOW: Custom warning.
              status
                  .getWarnings()
                  .add(
                      Warning.fromString(
                          "Recovery device deployment at high "
                              + "speed ("
                              + UnitGroup.UNITS_VELOCITY.toStringUnit(
                                  status.getRocketVelocity().length())
                              + ")."));
            }

            status.setLiftoff(true);
            status.getDeployedRecoveryDevices().add((RecoveryDevice) c);

            this.currentStepper = this.landingStepper;
            this.status = currentStepper.initialize(status);

            status.getFlightData().addEvent(event);
          }
          break;

        case GROUND_HIT:
          status.getFlightData().addEvent(event);
          break;

        case SIMULATION_END:
          ret = false;
          status.getFlightData().addEvent(event);
          break;

        case ALTITUDE:
          break;
      }
    }

    // If no motor has ignited, abort
    if (!status.isMotorIgnited()) {
      throw new MotorIgnitionException("No motors ignited.");
    }

    return ret;
  }