content: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  package org.apache.cloudstack.vm;
  
  import com.cloud.dc.DataCenter;
  import com.cloud.dc.DataCenterVO;
  import com.cloud.dc.dao.DataCenterDao;
  import com.cloud.host.Host;
  import com.cloud.host.HostVO;
  import com.cloud.host.dao.HostDao;
  import com.cloud.user.Account;
  import com.cloud.user.AccountService;
  import com.cloud.utils.DateUtil;
  import com.cloud.vm.ImportVMTaskVO;
  import com.cloud.vm.UserVmVO;
  import com.cloud.vm.dao.ImportVMTaskDao;
  import com.cloud.vm.dao.UserVmDao;
  import org.apache.cloudstack.api.command.admin.vm.ListImportVMTasksCmd;
  import org.apache.cloudstack.api.response.ImportVMTaskResponse;
  import org.apache.cloudstack.api.response.ListResponse;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  
  import javax.inject.Inject;
  import java.time.Duration;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  import java.util.TimeZone;
  
  import static org.apache.cloudstack.vm.ImportVmTask.Step.CloningInstance;
  import static org.apache.cloudstack.vm.ImportVmTask.Step.Completed;
  import static org.apache.cloudstack.vm.ImportVmTask.Step.ConvertingInstance;
  import static org.apache.cloudstack.vm.ImportVmTask.Step.Importing;
  import static org.apache.cloudstack.vm.ImportVmTask.Step.Prepare;
  
  public class ImportVmTasksManagerImpl implements ImportVmTasksManager {
  
      protected Logger logger = LogManager.getLogger(ImportVmTasksManagerImpl.class);
  
      @Inject
      private ImportVMTaskDao importVMTaskDao;
      @Inject
      private DataCenterDao dataCenterDao;
      @Inject
      private AccountService accountService;
      @Inject
      private HostDao hostDao;
      @Inject
      private UserVmDao userVmDao;
  
      public ImportVmTasksManagerImpl() {
      }
  
      @Override
      public ListResponse<ImportVMTaskResponse> listImportVMTasks(ListImportVMTasksCmd cmd) {
          Long zoneId = cmd.getZoneId();
          Long accountId = cmd.getAccountId();
          String vcenter = cmd.getVcenter();
          Long convertHostId = cmd.getConvertHostId();
          boolean listAll = cmd.isListAll();
          boolean showCompleted = cmd.isShowCompleted();
  
          List<ImportVMTaskVO> tasks;
          if (listAll) {
              tasks = importVMTaskDao.listAll();
          } else {
              tasks = importVMTaskDao.listImportVMTasks(zoneId, accountId, vcenter, convertHostId, showCompleted);
          }
  
          List<ImportVMTaskResponse> responses = new ArrayList<>();
          for (ImportVMTaskVO task : tasks) {
              responses.add(createImportVMTaskResponse(task));
          }
          ListResponse<ImportVMTaskResponse> listResponses = new ListResponse<>();
          listResponses.setResponses(responses, responses.size());
          return listResponses;
      }
  
      @Override
      public ImportVmTask createImportVMTaskRecord(DataCenter zone, Account owner, long userId, String displayName, String vcenter, String datacenterName, String sourceVMName, Host convertHost, Host importHost) {
          logger.debug("Creating import VM task entry for VM: {} for account {} on zone {} " +
                          "from the vCenter: {} / datacenter: {} / source VM: {}",
                  sourceVMName, owner.getAccountName(), zone.getName(), displayName, vcenter, datacenterName);
          ImportVMTaskVO importVMTaskVO = new ImportVMTaskVO(zone.getId(), owner.getAccountId(), userId, displayName,
                  vcenter, datacenterName, sourceVMName, convertHost.getId(), importHost.getId());
          return importVMTaskDao.persist(importVMTaskVO);
      }
  
      private String getStepDescription(ImportVMTaskVO importVMTaskVO, Host convertHost, Host importHost,
                                        ImportVMTaskVO.Step step, Date updatedDate) {
          String sourceVMName = importVMTaskVO.getSourceVMName();
          String vcenter = importVMTaskVO.getVcenter();
          String datacenter = importVMTaskVO.getDatacenter();
  
          StringBuilder stringBuilder = new StringBuilder();
          if (Completed == step) {
              stringBuilder.append("Completed at ").append(DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), updatedDate));
          } else {
              stringBuilder.append(String.format("[%s] ", DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), updatedDate)));
              if (CloningInstance == step) {
                  stringBuilder.append(String.format("Cloning source instance: %s on vCenter: %s / datacenter: %s", sourceVMName, vcenter, datacenter));
              } else if (ConvertingInstance == step) {
                  stringBuilder.append(String.format("Converting the cloned VMware instance to a KVM instance on the host: %s", convertHost.getName()));
              } else if (Importing == step) {
                  stringBuilder.append(String.format("Importing the converted KVM instance on the host: %s", importHost.getName()));
              } else if (Prepare == step) {
                  stringBuilder.append("Preparing to convert Vmware instance");
              }
          }
          return stringBuilder.toString();
      }
  
      @Override
      public void updateImportVMTaskStep(ImportVmTask importVMTask, DataCenter zone, Account owner, Host convertHost,
                                         Host importHost, Long vmId, ImportVmTask.Step step) {
          ImportVMTaskVO importVMTaskVO = (ImportVMTaskVO) importVMTask;
          logger.debug("Updating import VM task entry for VM: {} for account {} on zone {} " +
                          "from the vCenter: {} / datacenter: {} / source VM: {} to step: {}",
                  importVMTaskVO.getSourceVMName(), owner.getAccountName(), zone.getName(), importVMTaskVO.getDisplayName(),
                  importVMTaskVO.getVcenter(), importVMTaskVO.getDatacenter(), step);
          Date updatedDate = DateUtil.now();
          String description = getStepDescription(importVMTaskVO, convertHost, importHost, step, updatedDate);
          importVMTaskVO.setStep(step);
          importVMTaskVO.setDescription(description);
          importVMTaskVO.setUpdated(updatedDate);
          if (Completed == step) {
              Duration duration = Duration.between(importVMTaskVO.getCreated().toInstant(), updatedDate.toInstant());
              importVMTaskVO.setDuration(duration.toMillis());
              importVMTaskVO.setVmId(vmId);
          }
          importVMTaskDao.update(importVMTaskVO.getId(), importVMTaskVO);
      }
  
      @Override
      public boolean removeImportVMTask(long taskId) {
          return importVMTaskDao.remove(taskId);
      }
  
      private ImportVMTaskResponse createImportVMTaskResponse(ImportVMTaskVO task) {
          ImportVMTaskResponse response = new ImportVMTaskResponse();
          DataCenterVO zone = dataCenterDao.findById(task.getZoneId());
          if (zone != null) {
              response.setZoneId(zone.getUuid());
              response.setZoneName(zone.getName());
          }
          Account account = accountService.getAccount(task.getAccountId());
          if (account != null) {
              response.setAccountId(account.getUuid());
              response.setAccountName(account.getAccountName());
          }
          response.setVcenter(task.getVcenter());
          response.setDatacenterName(task.getDatacenter());
          response.setSourceVMName(task.getSourceVMName());
          response.setDisplayName(task.getDisplayName());
          response.setStep(getStepDisplayField(task.getStep()));
          response.setDescription(task.getDescription());
  
          Date updated = task.getUpdated();
          Date currentDate = new Date();
          if (updated != null && Completed != task.getStep()) {
              Duration stepDuration = Duration.between(updated.toInstant(), currentDate.toInstant());
              response.setStepDuration(getDurationDisplay(stepDuration.toMillis()));
          }
          if (Completed == task.getStep()) {
              response.setStepDuration(getDurationDisplay(task.getDuration()));
          } else {
              Duration totalDuration = Duration.between(task.getCreated().toInstant(), currentDate.toInstant());
              response.setDuration(getDurationDisplay(totalDuration.toMillis()));
          }
          HostVO host = hostDao.findById(task.getConvertHostId());
          if (host != null) {
              response.setConvertInstanceHostId(host.getUuid());
              response.setConvertInstanceHostName(host.getName());
          }
          if (task.getVmId() != null) {
              UserVmVO userVm = userVmDao.findById(task.getVmId());
              response.setVirtualMachineId(userVm.getUuid());
          }
          response.setCreated(task.getCreated());
          response.setLastUpdated(task.getUpdated());
          response.setObjectName("importvmtask");
          return response;
      }
  
      protected String getStepDisplayField(ImportVMTaskVO.Step step) {
          int totalSteps = ImportVMTaskVO.Step.values().length;
          return String.format("[%s/%s] %s", step.ordinal() + 1, totalSteps, step.name());
      }
  
      protected static String getDurationDisplay(Long durationMs) {
          if (durationMs == null) {
              return null;
          }
          long hours = durationMs / (1000 * 60 * 60);
          long minutes = (durationMs / (1000 * 60)) % 60;
          long seconds = (durationMs / 1000) % 60;
  
          StringBuilder result = new StringBuilder();
          if (hours > 0) {
              result.append(String.format("%s hs ", hours));
          }
          if (minutes > 0) {
              result.append(String.format("%s min ", minutes));
          }
          if (seconds > 0) {
              result.append(String.format("%s secs", seconds));
          }
          return result.toString();
      }
  }
  