@Inject
 public LaneMoveHandler(
     HasArea environment,
     EnvironmentServiceProvider serviceProvider,
     EnvironmentSharedStateAccess sharedState,
     EventBus eb,
     @Named("params.nonStopMode") int nonStopMode)
     throws UnavailableServiceException {
   super(environment, serviceProvider, sharedState);
   this.eventBus = eb;
   eb.subscribe(this);
   this.roadEnvironmentService =
       serviceProvider.getEnvironmentService(RoadEnvironmentService.class);
   this.speedService = serviceProvider.getEnvironmentService(SpeedService.class);
   this.nonStopMode = nonStopMode;
 }
  @Override
  public Input handle(Action action, UUID actor) throws ActionHandlingException {
    CellMove m = (CellMove) action;
    int prevSpeed = speedService.getAgentSpeed(actor);
    int maxSpeed = roadEnvironmentService.getMaxSpeed();
    int maxAccel = roadEnvironmentService.getMaxAccel();
    int maxDecel = roadEnvironmentService.getMaxDecel();

    // check move direction is positive or 0
    if (m.getY() < 0) {
      throw new ActionHandlingException("Cannot move backwards. Move was: " + m);
    }

    // check move is not too fast
    if (m.getY() > maxSpeed) {
      throw new ActionHandlingException(
          "Cannot move faster than the maximum speed (" + maxSpeed + "). Move was: " + m);
    }

    // check acceleration is not too fast
    if (m.getY() > prevSpeed) {
      if ((m.getY() - prevSpeed) > maxAccel) {
        throw new ActionHandlingException(
            "Cannot accelerate faster than the maximum acceleration ("
                + maxAccel
                + "). Move was: "
                + m
                + " and previous speed was "
                + prevSpeed);
      }
    }

    // check deceleration is not too fast
    if (m.getY() < prevSpeed) {
      if ((prevSpeed - m.getY()) > maxDecel) {
        throw new ActionHandlingException(
            "Cannot decelerate faster than the maximum deceleration ("
                + maxDecel
                + "). Move was: "
                + m
                + " and previous speed was "
                + prevSpeed);
      }
    }

    // check move sideways magnitude is 0 or 1
    if (Math.abs(m.getX()) > 1) {
      throw new ActionHandlingException(
          "Cannot change greater than one lane at once. Move was: " + m);
    }
    // cannot change lane without forward movement
    if (Math.abs(m.getX()) > 0 && (int) m.getY() == 0) {
      throw new ActionHandlingException("Cannot change lane while stationary");
    }

    RoadLocation start = (RoadLocation) getLocationService().getAgentLocation(actor);
    RoadLocation target = new RoadLocation(start.add(m));

    if (!target.in(environment.getArea())) {
      // check if it's a junction location
      if (target.getLane() == -1) {
        Integer exitPoint = null;
        Integer startOffset = MathsUtils.mod(start.getOffset(), roadEnvironmentService.getLength());
        Integer targetOffset =
            MathsUtils.mod(target.getOffset(), roadEnvironmentService.getLength());
        if (startOffset > targetOffset) {
          startOffset = startOffset - roadEnvironmentService.getLength();
        }
        for (int junction : roadEnvironmentService.getJunctionLocations()) {
          if ((startOffset <= junction) && (targetOffset >= junction)) {
            exitPoint = junction;
            logger.info("Agent " + actor + " left the road at " + exitPoint);
            eventBus.publish(new AgentLeftScenario(actor, exitPoint, SimTime.get()));
            // turning off means avoiding the possibility of crashing... ohwells: sliproads are
            // LOOOONG
            return null;
          }
        }
        logger.warn(
            "Agent "
                + actor
                + " tried to turn off using move "
                + m
                + " between "
                + start
                + " and "
                + target
                + " and offsets "
                + startOffset
                + ","
                + targetOffset
                + " but was not near a junction");
      }
      /*if ( (target.getLane()==-1) && (roadEnvironmentService.isJunctionOffset(target.getOffset())) ) {
      	// do stuff
      	logger.info("Agent " + actor + " left the road at " + target.getOffset());
      	eventBus.publish(new AgentLeftScenario(actor,target.getOffset(), SimTime.get()));
      	// turning off means avoiding the possibility of crashing... ohwells: sliproads are LOOOONG
      	return null;
      }
      else {*/
      try {
        final Move mNew = environment.getArea().getValidMove(start, m);
        target = new RoadLocation(start.add(mNew));
      } catch (EdgeException e) {
        throw new ActionHandlingException(e);
      }
      // }
    }
    this.getLocationService().setAgentLocation(actor, target);
    this.speedService.setAgentSpeed(actor, (int) m.getY());
    checks.add(new CollisionCheck(actor, start, target));

    logger.info(actor + " move: " + m);
    return null;
  }