/**
   * Task variation over time i.e. tasks started and completed over the months
   *
   * @return array with the no. of tasks started and completed over the months
   */
  @GET
  @Path("/taskVariation/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder taskVariationOverTime() {
    ResponseHolder response = new ResponseHolder();
    List list = new ArrayList();
    String[] MONTHS = {
      "Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    SimpleDateFormat ft = new SimpleDateFormat("M");

    InstanceStatPerMonth[] taskStatPerMonths = new InstanceStatPerMonth[12];
    for (int i = 0; i < taskStatPerMonths.length; i++) {
      taskStatPerMonths[i] = new InstanceStatPerMonth();
      taskStatPerMonths[i].setMonth(MONTHS[i]);
      taskStatPerMonths[i].setCompletedInstances(0);
      taskStatPerMonths[i].setStartedInstances(0);
    }
    // Get completed tasks
    List<HistoricTaskInstance> taskList =
        BPMNOSGIService.getHistoryService()
            .createHistoricTaskInstanceQuery()
            .taskTenantId(str)
            .finished()
            .list();

    for (HistoricTaskInstance instance : taskList) {
      int startTime = Integer.parseInt(ft.format(instance.getCreateTime()));
      int endTime = Integer.parseInt(ft.format(instance.getEndTime()));
      taskStatPerMonths[startTime - 1].setStartedInstances(
          taskStatPerMonths[startTime - 1].getStartedInstances() + 1);
      taskStatPerMonths[endTime - 1].setCompletedInstances(
          taskStatPerMonths[endTime - 1].getCompletedInstances() + 1);
    }
    // Get active/started tasks
    List<Task> taskActive =
        BPMNOSGIService.getTaskService().createTaskQuery().taskTenantId(str).active().list();
    for (Task instance : taskActive) {

      int startTime = Integer.parseInt(ft.format(instance.getCreateTime()));
      taskStatPerMonths[startTime - 1].setStartedInstances(
          taskStatPerMonths[startTime - 1].getStartedInstances() + 1);
    }

    // Get suspended tasks
    List<Task> taskSuspended =
        BPMNOSGIService.getTaskService().createTaskQuery().taskTenantId(str).suspended().list();
    for (Task instance : taskSuspended) {

      int startTime = Integer.parseInt(ft.format(instance.getCreateTime()));
      taskStatPerMonths[startTime - 1].setStartedInstances(
          taskStatPerMonths[startTime - 1].getStartedInstances() + 1);
    }
    for (int i = 0; i < taskStatPerMonths.length; i++) {
      list.add(taskStatPerMonths[i]);
    }
    response.setData(list);
    return response;
  }
  /**
   * Process variation over time i.e. tasks started and completed over the months
   *
   * @return array with the no. of processes started and completed over the months
   */
  @GET
  @Path("/processVariation/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder processVariationOverTime() {
    ResponseHolder response = new ResponseHolder();
    List list = new ArrayList();
    String[] MONTHS = {
      "Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    SimpleDateFormat ft = new SimpleDateFormat("M");
    InstanceStatPerMonth[] processStatPerMonths = new InstanceStatPerMonth[12];
    for (int i = 0; i < processStatPerMonths.length; i++) {
      processStatPerMonths[i] = new InstanceStatPerMonth();
      processStatPerMonths[i].setMonth(MONTHS[i]);
      processStatPerMonths[i].setCompletedInstances(0);
      processStatPerMonths[i].setStartedInstances(0);
    }

    // Get completed process instances
    List<HistoricProcessInstance> completedProcesses =
        BPMNOSGIService.getHistoryService()
            .createHistoricProcessInstanceQuery()
            .processInstanceTenantId(str)
            .finished()
            .list();
    for (HistoricProcessInstance instance : completedProcesses) {
      int startTime = Integer.parseInt(ft.format(instance.getStartTime()));
      int endTime = Integer.parseInt(ft.format(instance.getEndTime()));
      processStatPerMonths[startTime - 1].setStartedInstances(
          processStatPerMonths[startTime - 1].getStartedInstances() + 1);
      processStatPerMonths[endTime - 1].setCompletedInstances(
          processStatPerMonths[endTime - 1].getCompletedInstances() + 1);
    }
    // Get active process instances
    List<HistoricProcessInstance> activeProcesses =
        BPMNOSGIService.getHistoryService()
            .createHistoricProcessInstanceQuery()
            .processInstanceTenantId(str)
            .unfinished()
            .list();
    for (HistoricProcessInstance instance : activeProcesses) {
      int startTime = Integer.parseInt(ft.format(instance.getStartTime()));
      processStatPerMonths[startTime - 1].setStartedInstances(
          processStatPerMonths[startTime - 1].getStartedInstances() + 1);
    }

    for (int i = 0; i < processStatPerMonths.length; i++) {
      list.add(processStatPerMonths[i]);
    }
    response.setData(list);
    return response;
  }
  /**
   * Get the average time duration of completed processes
   *
   * @return list with the completed processes and the average time duration taken for each process
   */
  @GET
  @Path("/avgDurationToCompleteProcess/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder getAvgTimeDurationForCompletedProcesses() {
    List<ProcessDefinition> deployements =
        BPMNOSGIService.getRepositoryService()
            .createProcessDefinitionQuery()
            .processDefinitionTenantId(str)
            .list();

    ResponseHolder response = new ResponseHolder();
    List list = new ArrayList<>();

    for (ProcessDefinition instance : deployements) {
      CompletedProcesses bpmnProcessInstance = new CompletedProcesses();
      bpmnProcessInstance.setProcessDefinitionId(instance.getId());

      double totalTime = 0;
      double averageTime = 0;
      String processDefinitionID = instance.getId();

      HistoricProcessInstanceQuery historicProcessInstanceQuery =
          BPMNOSGIService.getHistoryService()
              .createHistoricProcessInstanceQuery()
              .processInstanceTenantId(str)
              .processDefinitionId(processDefinitionID)
              .finished();

      long noOfHistoricInstances = historicProcessInstanceQuery.count();

      if (noOfHistoricInstances == 0) {
      } else {
        List<HistoricProcessInstance> instanceList = historicProcessInstanceQuery.list();

        for (HistoricProcessInstance completedProcess : instanceList) {
          double timeDurationOfTask = completedProcess.getDurationInMillis();
          double timeInMins = timeDurationOfTask / (1000 * 60);
          totalTime += timeInMins;
        }
        averageTime = totalTime / noOfHistoricInstances;
        bpmnProcessInstance.setAverageTimeForCompletion(averageTime);
        list.add(bpmnProcessInstance);
      }
    }
    response.setData(list);
    return response;
  }
  /**
   * Get all deployed processes
   *
   * @return list with the processDefinitions of all deployed processes
   */
  @GET
  @Path("/allProcesses/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder getAllProcesses() {
    // Get a list of the deployed processes
    List<ProcessDefinition> deployements =
        BPMNOSGIService.getRepositoryService()
            .createProcessDefinitionQuery()
            .processDefinitionTenantId(str)
            .list();
    List listOfProcesses = new ArrayList<>();
    ResponseHolder response = new ResponseHolder();
    for (ProcessDefinition processDefinition : deployements) {
      listOfProcesses.add(processDefinition.getId());
    }

    response.setData(listOfProcesses);
    return response;
  }
 /**
  * Get the deployed processes count
  *
  * @return a list of deployed processes with their instance count
  */
 @GET
 @Path("/deployedProcessCount/")
 @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
 public ResponseHolder getDeployedProcesses() {
   List<ProcessDefinition> deployments =
       BPMNOSGIService.getRepositoryService()
           .createProcessDefinitionQuery()
           .processDefinitionTenantId(str)
           .list();
   List bpmnProcessInstancesList = new ArrayList<>();
   ResponseHolder response = new ResponseHolder();
   for (ProcessDefinition instance : deployments) {
     DeployedProcesses bpmnProcessInstance = new DeployedProcesses();
     bpmnProcessInstance.setProcessDefinitionId(instance.getId());
     String pId = instance.getId();
     long count1 = getCountOfHistoricProcessInstances(pId);
     long count2 = getCountOfRunningProcessInstances(pId);
     long noOfInstances = count1 + count2;
     bpmnProcessInstance.setDeployedProcessCount(noOfInstances);
     bpmnProcessInstancesList.add(bpmnProcessInstance);
   }
   response.setData(bpmnProcessInstancesList);
   return response;
 }
  /**
   * Average task duration for completed processes
   *
   * @param pId processDefintionId of the process selected to view the average time duration for
   *     each task
   * @return list of completed tasks with the average time duration for the selected process
   */
  @GET
  @Path("/avgTaskDurationForCompletedProcess/{pId}")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder avgTaskTimeDurationForCompletedProcesses(@PathParam("pId") String pId) {
    long countOfProcesses =
        BPMNOSGIService.getRepositoryService()
            .createProcessDefinitionQuery()
            .processDefinitionTenantId(str)
            .processDefinitionId(pId)
            .count();
    if (countOfProcesses == 0) {
      throw new ActivitiObjectNotFoundException(
          "Could not find process with process definition id '" + pId + "'.");
    }

    ResponseHolder response = new ResponseHolder();
    List taskListForProcess = new ArrayList<>();
    HashMap<String, Long> map = new HashMap<String, Long>();
    // Get the number of completed/finished process instance for each process definition
    HistoricProcessInstanceQuery historicProcessInstanceQuery =
        BPMNOSGIService.getHistoryService()
            .createHistoricProcessInstanceQuery()
            .processInstanceTenantId(str)
            .processDefinitionId(pId)
            .finished();
    // Get the count of the complete process instances
    long noOfHistoricInstances = historicProcessInstanceQuery.count();

    // If the deployed process doesnot have any completed process instances --> Ignore
    if (noOfHistoricInstances == 0) {
      response.setData(taskListForProcess);
    }
    // If the deployed process has completed process instances --> then
    else {

      BPMNTaskInstance tInstance = new BPMNTaskInstance();
      // Get the list of completed tasks/activities in the completed process instance by passing the
      // process definition id of the process
      List<HistoricTaskInstance> taskList =
          BPMNOSGIService.getHistoryService()
              .createHistoricTaskInstanceQuery()
              .taskTenantId(str)
              .processDefinitionId(pId)
              .processFinished()
              .list();
      // Iterate through each completed task/activity and get the task name and duration
      for (HistoricTaskInstance taskInstance : taskList) {
        // Get the task name
        String taskKey = taskInstance.getTaskDefinitionKey();
        // Get the time duration taken for the task to be completed
        long taskDuration = taskInstance.getDurationInMillis();

        if (map.containsKey(taskKey)) {
          long tt = map.get(taskKey);
          map.put(taskKey, taskDuration + tt);
        } else {
          map.put(taskKey, taskDuration);
        }
        // Iterating Task List finished
      }
      Iterator iterator = map.keySet().iterator();
      while (iterator.hasNext()) {
        String key = iterator.next().toString();
        double value = map.get(key) / noOfHistoricInstances;
        tInstance = new BPMNTaskInstance();
        tInstance.setTaskDefinitionKey(key);
        tInstance.setAverageTimeForCompletion(value);
        taskListForProcess.add(tInstance);
      }

      response.setData(taskListForProcess);
    }
    return response;
  }
  /**
   * Get the number of Task Instances with various states States: Completed , Active, Suspended,
   * Failed
   *
   * @return list with the states and the count of task instances in each state
   */
  @GET
  @Path("/taskStatusCount/")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public ResponseHolder getCountOfTaskInstanceStatus() {

    List taskCountList = new ArrayList<>();
    ResponseHolder response = new ResponseHolder();
    ProcessTaskCount completedTaskInstances,
        activeTaskInstances,
        suspendedTaskInstances,
        failedTaskInstances;

    TaskQuery taskQuery = BPMNOSGIService.getTaskService().createTaskQuery();
    long countOfCompletedTaskInstances =
        BPMNOSGIService.getHistoryService()
            .createHistoricTaskInstanceQuery()
            .taskTenantId(str)
            .finished()
            .count();

    long countOfActiveTaskInstances = taskQuery.taskTenantId(str).active().count();

    long countOfSuspendedTaskInstances = taskQuery.taskTenantId(str).suspended().count();
    // Check on this
    long countOfFailedTaskInstances =
        BPMNOSGIService.getManagementService()
            .createJobQuery()
            .jobTenantId(str)
            .withException()
            .count();

    if (countOfCompletedTaskInstances == 0
        && countOfActiveTaskInstances == 0
        && countOfSuspendedTaskInstances == 0
        && countOfFailedTaskInstances == 0) {
      response.setData(taskCountList);
    } else {
      completedTaskInstances = new ProcessTaskCount();
      completedTaskInstances.setStatusOfProcessOrTask("Completed");
      completedTaskInstances.setCount(countOfCompletedTaskInstances);
      taskCountList.add(completedTaskInstances);

      activeTaskInstances = new ProcessTaskCount();
      activeTaskInstances.setStatusOfProcessOrTask("Active");
      activeTaskInstances.setCount(countOfActiveTaskInstances);
      taskCountList.add(activeTaskInstances);

      suspendedTaskInstances = new ProcessTaskCount();
      suspendedTaskInstances.setStatusOfProcessOrTask("Suspended");
      suspendedTaskInstances.setCount(countOfSuspendedTaskInstances);
      taskCountList.add(suspendedTaskInstances);

      failedTaskInstances = new ProcessTaskCount();
      failedTaskInstances.setStatusOfProcessOrTask("Failed");
      failedTaskInstances.setCount(countOfFailedTaskInstances);
      taskCountList.add(failedTaskInstances);

      response.setData(taskCountList);
    }
    return response;
  }