/**
   * Creates instances of CloudSim's Cloudlet class from a customer's utilization profile.
   *
   * @param ugr the utilization profile.
   * @param brokerId the id of the broker that owns the cloudlets.
   * @param numOfVms the number of virtual machines.
   * @return a list of Cloudlet instances.
   * @since 1.0
   */
  static List<Cloudlet> createCloudlets(UtilizationProfile ugr, int brokerId, long numOfVms)
      throws IOException, ServiceDeniedException {
    List<Cloudlet> list = new ArrayList<Cloudlet>();

    for (int i = 0; i < numOfVms; i++) {

      Optional<UtilizationModel> cpu =
          UTILIZATION_MODEL.getExtensionInstanceByName(ugr.getUtilizationModelCpuAlias());

      if (!cpu.isPresent()) {
        Dialog.showErrorMessage(
            null,
            format(
                "Error on loading the CPU utilization model [%s]",
                ugr.getUtilizationModelCpuAlias()));
        return null;
      }

      Optional<UtilizationModel> ram =
          UTILIZATION_MODEL.getExtensionInstanceByName(ugr.getUtilizationModelRamAlias());

      if (!ram.isPresent()) {
        Dialog.showErrorMessage(
            null,
            format(
                "Error on loading the RAM utilization model [%s]",
                ugr.getUtilizationModelRamAlias()));
        return null;
      }

      Optional<UtilizationModel> bw =
          UTILIZATION_MODEL.getExtensionInstanceByName(ugr.getUtilizationModelBwAlias());

      if (!bw.isPresent()) {
        Dialog.showErrorMessage(
            null,
            format(
                "Error on loading the bandwidth utilization model [%s]",
                ugr.getUtilizationModelBwAlias()));
        return null;
      }

      Cloudlet cloudlet =
          new Cloudlet(
              i,
              (long) ((long) ugr.getLength() * RandomNumberGenerator.getRandomNumbers(1).get(0)),
              ugr.getCloudletsPesNumber(),
              ugr.getFileSize(),
              ugr.getOutputSize(),
              cpu.get(),
              ram.get(),
              bw.get());

      cloudlet.setUserId(brokerId);
      cloudlet.setVmId(i);
      list.add(cloudlet);
    }

    return list;
  }
 /**
  * Returns one cloudlet to migrate to another vm.
  *
  * @return one running cloudlet
  * @pre $none
  * @post $none
  */
 @Override
 public Cloudlet migrateCloudlet() {
   ResCloudlet rcl = getCloudletExecList().remove(0);
   rcl.finalizeCloudlet();
   Cloudlet cl = rcl.getCloudlet();
   usedPes -= cl.getNumberOfPes();
   return cl;
 }
  /**
   * Receives an cloudlet to be executed in the VM managed by this scheduler.
   *
   * @param cloudlet the submited cloudlet
   * @param fileTransferTime time required to move the required files from the SAN to the VM
   * @return expected finish time of this cloudlet, or 0 if it is in the waiting queue
   * @pre gl != null
   * @post $none
   */
  @Override
  public double cloudletSubmit(Cloudlet cloudlet, double fileTransferTime) {
    // it can go to the exec list
    if ((currentCpus - usedPes) >= cloudlet.getNumberOfPes()) {
      ResCloudlet rcl = new ResCloudlet(cloudlet);
      rcl.setCloudletStatus(Cloudlet.INEXEC);
      for (int i = 0; i < cloudlet.getNumberOfPes(); i++) {
        rcl.setMachineAndPeId(0, i);
      }
      getCloudletExecList().add(rcl);
      usedPes += cloudlet.getNumberOfPes();
    } else { // no enough free PEs: go to the waiting queue
      ResCloudlet rcl = new ResCloudlet(cloudlet);
      rcl.setCloudletStatus(Cloudlet.QUEUED);
      getCloudletWaitingList().add(rcl);
      return 0.0;
    }

    // calculate the expected time for cloudlet completion
    double capacity = 0.0;
    int cpus = 0;
    for (Double mips : getCurrentMipsShare()) {
      capacity += mips;
      if (mips > 0) {
        cpus++;
      }
    }

    currentCpus = cpus;
    capacity /= cpus;

    // use the current capacity to estimate the extra amount of
    // time to file transferring. It must be added to the cloudlet length
    double extraSize = capacity * fileTransferTime;
    long length = cloudlet.getCloudletLength();
    length += extraSize;
    cloudlet.setCloudletLength(length);
    return cloudlet.getCloudletLength() / capacity;
  }