/** Process the form to create a new custom and external KPI. */
  public Result processCreate() {

    // bind the form
    Form<CustomExternalKpiFormData> boundForm = customExternalKpiFormTemplate.bindFromRequest();

    // get the object type
    String objectType = boundForm.data().get("objectType");

    if (boundForm.hasErrors()) {
      return ok(views.html.admin.kpi.create.render(objectType, boundForm));
    }

    CustomExternalKpiFormData customExternalKpiFormData = boundForm.get();

    KpiDefinition kpiDefinition = customExternalKpiFormData.constructKpiDefinition();

    kpiDefinition.mainKpiValueDefinition.save();
    kpiDefinition.additional1KpiValueDefinition.save();
    kpiDefinition.additional2KpiValueDefinition.save();
    kpiDefinition.save();

    customExternalKpiFormData.mainName.persist(getI18nMessagesPlugin());
    customExternalKpiFormData.additional1Name.persist(getI18nMessagesPlugin());
    customExternalKpiFormData.additional2Name.persist(getI18nMessagesPlugin());

    reloadKpiDefinition(kpiDefinition.uid);

    Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.create.successful"));

    return redirect(controllers.admin.routes.KpiManagerController.view(kpiDefinition.id));
  }
  /**
   * Delete a custom KPI.
   *
   * @param kpiDefinitionId the KPI definition id
   */
  public Result delete(Long kpiDefinitionId) {

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    if (!kpiDefinition.isStandard) {

      // cancel the scheduler
      kpi.cancel();

      // delete the values and data
      deleteKpiValueDefinition(kpiDefinition.mainKpiValueDefinition);
      deleteKpiValueDefinition(kpiDefinition.additional1KpiValueDefinition);
      deleteKpiValueDefinition(kpiDefinition.additional2KpiValueDefinition);

      // delete the colors
      if (kpiDefinition.kpiColorRules != null) {
        for (KpiColorRule kpiColorRule : kpiDefinition.kpiColorRules) {
          kpiColorRule.doDelete();
        }
      }

      kpiDefinition.deleted = true;
      kpiDefinition.save();

      Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.delete.successful"));

    } else {
      Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.delete.error"));
    }

    return redirect(controllers.admin.routes.KpiManagerController.index());
  }
  /** Process the edit form of the scheduler of a KPI definition. */
  public Result saveScheduler() {

    // bind the form
    Form<KpiSchedulerFormData> boundForm = kpiSchedulerFormTemplate.bindFromRequest();

    // get the KPI
    Long kpiDefinitionId = Long.valueOf(boundForm.data().get("id"));
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    if (boundForm.hasErrors()) {
      return ok(views.html.admin.kpi.editScheduler.render(kpiDefinition, kpi, boundForm));
    }

    KpiSchedulerFormData kpiSchedulerFormData = boundForm.get();

    kpiSchedulerFormData.fill(kpiDefinition);
    kpiDefinition.update();

    reloadKpiDefinition(kpiDefinition.uid);

    Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.editscheduler.successful"));

    return redirect(controllers.admin.routes.KpiManagerController.view(kpiDefinition.id));
  }
  /**
   * Change the order of a KPI definition comparing to the other KPIs with the same object type.
   *
   * @param kpiDefinitionId the KPI definition id
   * @param isDecrement if true then we decrement the order, else we increment it
   */
  public Result changeOrder(Long kpiDefinitionId, Boolean isDecrement) {

    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);

    KpiDefinition kpiDefinitionToReverse = null;
    if (isDecrement) {
      kpiDefinitionToReverse =
          KpiDefinition.getPrevious(kpiDefinition.objectType, kpiDefinition.order);
    } else {
      kpiDefinitionToReverse = KpiDefinition.getNext(kpiDefinition.objectType, kpiDefinition.order);
    }

    if (kpiDefinitionToReverse != null) {

      Integer newOrder = kpiDefinitionToReverse.order;

      kpiDefinitionToReverse.order = kpiDefinition.order;
      kpiDefinitionToReverse.save();

      kpiDefinition.order = newOrder;
      kpiDefinition.save();
    }

    return redirect(controllers.admin.routes.KpiManagerController.index());
  }
  /** List of all KPI definitions sorted by object type. */
  public Result index() {

    List<KpiDefinition> kpiDefinitions = KpiDefinition.getAll();

    Map<String, Table<KpiDefinitionListView>> tables =
        new HashMap<String, Table<KpiDefinitionListView>>();
    Map<String, List<KpiDefinitionListView>> kpiDefinitionListViews =
        new HashMap<String, List<KpiDefinitionListView>>();

    if (kpiDefinitions != null && kpiDefinitions.size() > 0) {

      for (KpiDefinition kpiDefinition : kpiDefinitions) {

        if (!kpiDefinitionListViews.containsKey(kpiDefinition.objectType)) {
          kpiDefinitionListViews.put(
              kpiDefinition.objectType, new ArrayList<KpiDefinitionListView>());
        }

        kpiDefinitionListViews
            .get(kpiDefinition.objectType)
            .add(new KpiDefinitionListView(kpiDefinition, getKpiService()));
      }

      for (Map.Entry<String, List<KpiDefinitionListView>> entry :
          kpiDefinitionListViews.entrySet()) {
        tables.put(
            entry.getKey(),
            this.getTableProvider().get().kpiDefinition.templateTable.fill(entry.getValue()));
      }
    }

    return ok(views.html.admin.kpi.index.render(tables));
  }
  /**
   * Form to manage (add or edit) a KPI color rule.
   *
   * @param kpiDefinitionId the KPI definition id
   * @param kpiColorRuleId the KPI color rule id, set 0 for the add case
   */
  public Result manageRule(Long kpiDefinitionId, Long kpiColorRuleId) {

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    // initiate the form with the template
    Form<KpiColorRuleFormData> form = kpiColorRuleFormTemplate;

    // edit case: inject values
    if (!kpiColorRuleId.equals(Long.valueOf(0))) {

      // get the KPI color rule
      KpiColorRule kpiColorRule = KpiColorRule.getById(kpiColorRuleId);

      form =
          kpiColorRuleFormTemplate.fill(
              new KpiColorRuleFormData(kpiColorRule, getI18nMessagesPlugin()));
    }

    return ok(
        views.html.admin.kpi.manageRule.render(
            kpiDefinition,
            kpi,
            form,
            Color.getColorsAsValueHolderCollection(getI18nMessagesPlugin())));
  }
  /**
   * Form to edit the main data of a KPI value definition.
   *
   * @param kpiValueDefinitionId the KPI value definition
   * @param valueType the value type (main, additional1, additional2)
   */
  public Result editValue(Long kpiValueDefinitionId, String valueType) {

    // get the KPI value
    KpiValueDefinition kpiValueDefinition = KpiValueDefinition.getById(kpiValueDefinitionId);

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiValueDefinition.getKpiDefinition().id);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    Form<KpiValueDefinitionFormData> form = null;

    if (kpiDefinition.isStandard) {
      form =
          standardKpiValueDefinitionFormTemplate.fill(
              new KpiValueDefinitionFormData(kpiValueDefinition, getI18nMessagesPlugin()));
    } else {
      form =
          customKpiValueDefinitionFormTemplate.fill(
              new KpiValueDefinitionFormData(kpiValueDefinition, getI18nMessagesPlugin()));
    }

    return ok(
        views.html.admin.kpi.editValue.render(
            kpiDefinition,
            kpi,
            kpiValueDefinition,
            valueType,
            form,
            getRenderTypesAsValueHolderCollection()));
  }
  /**
   * Form to edit the parameters of the scheduler of a KPI definition.
   *
   * <p>Possible only if the scheduler is active.
   *
   * @param kpiDefinitionId the KPI definition id
   */
  public Result editScheduler(Long kpiDefinitionId) {

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    Form<KpiSchedulerFormData> form =
        kpiSchedulerFormTemplate.fill(new KpiSchedulerFormData(kpiDefinition));

    return ok(views.html.admin.kpi.editScheduler.render(kpiDefinition, kpi, form));
  }
  /** Process the manage form of a KPI color rule. */
  public Result saveRule() {

    // bind the form
    Form<KpiColorRuleFormData> boundForm = kpiColorRuleFormTemplate.bindFromRequest();

    // get the KPI
    Long kpiDefinitionId = Long.valueOf(boundForm.data().get("kpiDefinitionId"));
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    if (boundForm.hasErrors()) {
      return ok(
          views.html.admin.kpi.manageRule.render(
              kpiDefinition,
              kpi,
              boundForm,
              Color.getColorsAsValueHolderCollection(getI18nMessagesPlugin())));
    }

    KpiColorRuleFormData kpiColorRuleFormData = boundForm.get();

    KpiColorRule kpiColorRule = null;

    if (kpiColorRuleFormData.kpiColorRuleId == null) { // create case

      kpiColorRule = new KpiColorRule();

      kpiColorRule.kpiDefinition = kpiDefinition;
      kpiColorRule.order = KpiColorRule.getLastOrder(kpiDefinition.id) + 1;

      kpiColorRuleFormData.fill(kpiColorRule);

      kpiColorRule.save();

      Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.rule.add.successful"));

    } else { // edit case

      kpiColorRule = KpiColorRule.getById(kpiColorRuleFormData.kpiColorRuleId);

      kpiColorRuleFormData.fill(kpiColorRule);

      kpiColorRule.update();

      Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.rule.edit.successful"));
    }

    kpiColorRuleFormData.renderLabel.persist(getI18nMessagesPlugin());

    reloadKpiDefinition(kpiDefinition.uid);

    return redirect(controllers.admin.routes.KpiManagerController.view(kpiDefinition.id));
  }
  /**
   * Delete the scheduler of a KPI definition.
   *
   * @param kpiDefinitionId the KPI definition id
   */
  public Result deleteScheduler(Long kpiDefinitionId) {

    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);

    kpiDefinition.schedulerFrequency = null;
    kpiDefinition.schedulerRealTime = null;
    kpiDefinition.schedulerStartTime = null;
    kpiDefinition.save();

    reloadKpiDefinition(kpiDefinition.uid);

    Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.scheduler.delete"));

    return redirect(controllers.admin.routes.KpiManagerController.view(kpiDefinitionId));
  }
  /**
   * Display the details of a KPI definition.
   *
   * @param kpiDefinitionId the KPI definition id
   */
  public Result view(Long kpiDefinitionId) {

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiDefinitionId);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    // create the table values
    List<KpiValueDefinitionListView> kpiValueDefinitionListView =
        new ArrayList<KpiValueDefinitionListView>();
    kpiValueDefinitionListView.add(
        new KpiValueDefinitionListView(kpiDefinition.mainKpiValueDefinition, DataType.MAIN));
    if (kpi.hasBoxDisplay()) {
      kpiValueDefinitionListView.add(
          new KpiValueDefinitionListView(
              kpiDefinition.additional1KpiValueDefinition, DataType.ADDITIONAL1));
      kpiValueDefinitionListView.add(
          new KpiValueDefinitionListView(
              kpiDefinition.additional2KpiValueDefinition, DataType.ADDITIONAL2));
    }
    Table<KpiValueDefinitionListView> valuesTable =
        this.getTableProvider()
            .get()
            .kpiValueDefinition
            .templateTable
            .fill(kpiValueDefinitionListView);

    // create the color rules table
    List<KpiColorRuleListView> kpiColorRuleListView = new ArrayList<KpiColorRuleListView>();
    for (KpiColorRule kpiColorRule : kpiDefinition.kpiColorRules) {
      kpiColorRuleListView.add(new KpiColorRuleListView(kpiColorRule, getI18nMessagesPlugin()));
    }
    Table<KpiColorRuleListView> rulesTable =
        this.getTableProvider().get().kpiColorRule.templateTable.fill(kpiColorRuleListView);

    return ok(views.html.admin.kpi.view.render(kpiDefinition, kpi, valuesTable, rulesTable));
  }
  /** Process the edit form of a KPI value definition. */
  public Result saveValue() {

    // get the KPI value
    Long kpiValueDefinitionId = Long.valueOf(request().body().asFormUrlEncoded().get("id")[0]);
    KpiValueDefinition kpiValueDefinition = KpiValueDefinition.getById(kpiValueDefinitionId);

    // get the KPI
    KpiDefinition kpiDefinition = KpiDefinition.getById(kpiValueDefinition.getKpiDefinition().id);
    Kpi kpi = new Kpi(kpiDefinition, getKpiService());

    // bind the form
    Form<KpiValueDefinitionFormData> boundForm = null;
    if (kpiDefinition.isStandard) {
      boundForm = standardKpiValueDefinitionFormTemplate.bindFromRequest();
    } else {
      boundForm = customKpiValueDefinitionFormTemplate.bindFromRequest();
    }

    // get the value type
    String valueType = boundForm.data().get("valueType");

    if (boundForm.hasErrors()) {
      return ok(
          views.html.admin.kpi.editValue.render(
              kpiDefinition,
              kpi,
              kpiValueDefinition,
              valueType,
              boundForm,
              getRenderTypesAsValueHolderCollection()));
    }

    KpiValueDefinitionFormData kpiValueDefinitionFormData = boundForm.get();

    if (kpiValueDefinitionFormData.renderType.equals(RenderType.PATTERN.name())
        && (kpiValueDefinitionFormData.renderPattern == null
            || kpiValueDefinitionFormData.renderPattern.equals(""))) {
      boundForm.reject(
          "renderPattern", Msg.get("object.kpi_value_definition.render_pattern.invalid"));
      return ok(
          views.html.admin.kpi.editValue.render(
              kpiDefinition,
              kpi,
              kpiValueDefinition,
              valueType,
              boundForm,
              getRenderTypesAsValueHolderCollection()));
    }

    kpiValueDefinitionFormData.fill(kpiValueDefinition, !kpiDefinition.isStandard);
    kpiValueDefinition.update();

    if (!kpiDefinition.isStandard) {
      kpiValueDefinitionFormData.name.persist(getI18nMessagesPlugin());
    }

    reloadKpiDefinition(kpiDefinition.uid);

    Utilities.sendSuccessFlashMessage(Msg.get("admin.kpi.value.edit.successful"));

    return redirect(controllers.admin.routes.KpiManagerController.view(kpiDefinition.id));
  }