/**
   * Create a number of ride offers from list of DTOs. (Bulkadd) This is used for performance test,
   * when we do not want to measure http overhead when adding multiple requests
   *
   * @param request
   * @return
   */
  @POST
  @Path("bulkadd")
  public Response addOffers(String json) {

    DriverUndertakesRideControllerLocal durcl = lookupDriverUndertakesRideControllerBean();
    RideOfferDTO[] dtos;
    try {
      dtos = jacksonMapper.readValue(json, RideOfferDTO[].class);
    } catch (IOException e) {

      // TODO: log error!
      return Response.status(Response.Status.BAD_REQUEST).build();
    }

    for (RideOfferDTO dto : dtos) {

      int updateResult =
          durcl.addRide(
              dto.getCustomerId().intValue(),
              locationConverter.point(dto.getStartLocation()),
              locationConverter.point(dto.getEndLocation()),
              // intermediate Points currently left out...
              new Point[0], // Point[] intermediate route
              null, // Have to know DriveId to add waypoints!
              new Date(dto.getStartTime().getTime()),
              dto.getComment(),
              null, // no acceptable Detour Minutes
              dto.getAcceptableDetourKM(),
              null, // no Acceptable Detour
              // In Percent(),
              dto.getOfferedSeatsNo(),
              // StringEscapeUtils.unescapeHtml(r.getStartptAddress())
              dto.getStartLocation().getAddress(),
              // StringEscapeUtils.unescapeHtml(r.getEndptAddress())))
              dto.getEndLocation().getAddress());

      if (updateResult == -1) {
        return Response.status(Response.Status.BAD_REQUEST).build();
      }

      // to add waypoints, we'll have to get hold of the rideId
      Integer rideId = updateResult;
      DriverUndertakesRideEntity ride = durcl.getDriveByDriveId(rideId);
      WaypointDTOConverter waypointDTOConverter = new WaypointDTOConverter();

      // add waypoints
      for (WaypointDTO wDTO : dto.getWayPoints()) {
        WaypointEntity wEntity = waypointDTOConverter.waypointEntity(wDTO, ride);
        durcl.addWaypoint(rideId, wEntity, wDTO.getRouteIdx());
      }
    }
    return Response.status(Response.Status.ACCEPTED).build();
  }
  /**
   * Remove (or rather invalidate) a customer. Removing a customer means, that his personal data
   * will be overwritten.
   *
   * <p>Note that this will be called inside a transaction explicitely.
   *
   * @param custId
   */
  public void removeCustomer(int custId) {

    logger.info("removeCustomer : " + custId);
    startUserTransaction();

    // TODO: make sure that all related entities are deleted, too.
    CustomerEntity ce = em.find(CustomerEntity.class, custId);

    // avoid trivialities
    if (ce == null) {
      logger.warning("Unable to retrieve user for custId " + custId + " cannot remove customer");
      return;
    }

    // TODO: remove all those ride request that can still be removed,
    // and invalidate the rest
    List<RiderUndertakesRideEntity> allRides =
        riderUndertakesRideControllerBean.getRidesForCustomer(ce);

    for (RiderUndertakesRideEntity re : allRides) {

      if (riderUndertakesRideControllerBean.isRemovable(re.getRiderrouteId())) {
        // delete all rides that can be deleted
        logger.info("Deleting Ride " + re.getRiderrouteId());
        riderUndertakesRideControllerBean.removeRide(re.getRiderrouteId());
      } else {
        // invalidate all rides that cannot be deleted
        logger.info("Invalidating Ride " + re.getRiderrouteId());
        riderUndertakesRideControllerBean.invalidateRide(re.getRiderrouteId());
      }
    } // for (RiderUndertakesRideEntity re: allRides)

    // TODO: remove all those ride request that can still be removed,
    // and invalidate the rest
    List<DriverUndertakesRideEntity> allDrives =
        driverUndertakesRideControllerBean.getDrivesForDriver(ce.getCustNickname());

    for (DriverUndertakesRideEntity due : allDrives) {

      if (driverUndertakesRideControllerBean.isDeletable(due.getRideId())) {
        // delete all drives that can be deleted
        logger.info("Invalidating Ride " + due.getRideId());
        driverUndertakesRideControllerBean.invalidateRide(due.getRideId());
      } else {
        // invalidate all rides that cannot be deleted
        logger.info("Invalidating Drive " + due.getRideId());
        driverUndertakesRideControllerBean.invalidateRide(due.getRideId());
      }
    } // for (RiderUndertakesRideEntity re: allRides)

    // TODO:
    // overwrite valid data for this user with randomized data

    String random = "" + Math.random();
    String ts = "" + System.currentTimeMillis();
    String seed = "deleted_user" + random + ":" + ts;

    // set firstname, lastname and gender
    this.setBasePersonalData(custId, seed, seed, '-', null);
    // invalidate dob, email , cellphone, landline phone
    // address data, smoker data, licensedate
    this.setPersonalData(
        custId,
        seed, // mock firstName
        seed,
        'x',
        null, // mock date of birth
        seed, // mock email
        false,
        seed, // mock mobile phone
        false,
        seed, // mock landline
        seed, // mock cust_addr street
        seed, // mock zipcode
        seed, // mock City
        'n', // mock smokerprefs
        null, // mock licensedate
        null, // mock preferred language
        UnitOfLength.KILOMETER.getKey());

    // invalidate nickname and password
    this.setNickname(custId, seed);
    this.setPassword(custId, seed);

    em.merge(ce);
    em.persist(ce);
    //
    // do not remove the customer, only overwrite the data
    //
    // em.remove(e);
    commitUserTransaction();
  }