/** Process the form to create/edit an allocation with an activity. */
  @With(CheckActorExists.class)
  @Dynamic(IMafConstants.ACTOR_EDIT_DYNAMIC_PERMISSION)
  public Result processManageAllocatedActivity() {

    // bind the form
    Form<TimesheetActivityAllocatedActorFormData> boundForm =
        allocatedActivityFormTemplate.bindFromRequest();

    // get the actor
    Long id = Long.valueOf(boundForm.data().get("id"));
    Actor actor = ActorDao.getActorById(id);

    if (boundForm.hasErrors()
        || this.getCustomAttributeManagerService()
            .validateValues(boundForm, TimesheetActivityAllocatedActor.class)) {
      return ok(views.html.core.actor.allocated_activity_manage.render(actor, boundForm));
    }

    TimesheetActivityAllocatedActorFormData allocatedActivityFormData = boundForm.get();

    TimesheetActivityAllocatedActor allocatedActivity = null;

    if (allocatedActivityFormData.allocatedActivityId == null) { // create
      // case

      allocatedActivity = new TimesheetActivityAllocatedActor();
      allocatedActivityFormData.fill(allocatedActivity);
      allocatedActivity.save();

      Utilities.sendSuccessFlashMessage(Msg.get("core.actor.allocated_activity.add.successful"));

    } else { // edit case

      allocatedActivity =
          TimesheetDao.getTimesheetActivityAllocatedActorById(
              allocatedActivityFormData.allocatedActivityId);

      // security: the actor must be related to the object
      if (!allocatedActivity.actor.id.equals(id)) {
        return forbidden(views.html.error.access_forbidden.render(""));
      }

      allocatedActivityFormData.fill(allocatedActivity);
      allocatedActivity.update();

      Utilities.sendSuccessFlashMessage(Msg.get("core.actor.allocated_activity.edit.successful"));
    }

    // save the custom attributes
    this.getCustomAttributeManagerService()
        .validateAndSaveValues(
            boundForm, TimesheetActivityAllocatedActor.class, allocatedActivity.id);

    return redirect(controllers.core.routes.ActorController.allocationDetails(id, 0, 0, false));
  }
  /**
   * Delete an allocated activity.
   *
   * @param id the actor id
   * @param allocatedActivityId the allocated activity id
   */
  @With(CheckActorExists.class)
  @Dynamic(IMafConstants.ACTOR_EDIT_DYNAMIC_PERMISSION)
  public Result deleteAllocatedActivity(Long id, Long allocatedActivityId) {

    // get the allocated activity
    TimesheetActivityAllocatedActor allocatedActivity =
        TimesheetDao.getTimesheetActivityAllocatedActorById(allocatedActivityId);

    // security: the actor must be related to the object
    if (!allocatedActivity.actor.id.equals(id)) {
      return forbidden(views.html.error.access_forbidden.render(""));
    }

    // set the delete flag to true
    allocatedActivity.doDelete();

    Utilities.sendSuccessFlashMessage(Msg.get("core.actor.allocated_activity.delete.successful"));

    return redirect(controllers.core.routes.ActorController.allocationDetails(id, 0, 0, false));
  }
  /**
   * Construct the side bar.
   *
   * @param id the actor id
   * @param currentType the current menu item type, useful to select the correct item
   * @param securityService the security service
   */
  public static SideBar getSideBar(
      Long id, MenuItemType currentType, ISecurityService securityService) {

    SideBar sideBar = new SideBar();

    sideBar.addMenuItem(
        new ClickableMenuItem(
            "core.actor.sidebar.overview",
            controllers.core.routes.ActorController.view(id),
            "fa fa-search-plus",
            currentType.equals(MenuItemType.OVERVIEW)));

    if (securityService.dynamic(IMafConstants.ACTOR_VIEW_DYNAMIC_PERMISSION, "")) {

      sideBar.addMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.portfolio_entries",
              controllers.core.routes.ActorController.listPortfolioEntries(id, 0),
              "fa fa-sticky-note",
              currentType.equals(MenuItemType.INITIATIVES)));

      sideBar.addMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.portfolios",
              controllers.core.routes.ActorController.listPortfolios(id, 0),
              "fa fa-folder",
              currentType.equals(MenuItemType.PORTFOLIOS)));

      HeaderMenuItem allocationMenu =
          new HeaderMenuItem(
              "core.actor.sidebar.allocation",
              "fa fa-book",
              currentType.equals(MenuItemType.ALLOCATION));

      allocationMenu.addSubMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.allocation.overview",
              controllers.core.routes.ActorController.allocation(id),
              "fa fa-tachometer",
              false));

      allocationMenu.addSubMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.allocation.details",
              controllers.core.routes.ActorController.allocationDetails(id, 0, 0, false),
              "fa fa-search-plus",
              false));

      allocationMenu.addSubMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.allocation.capacity",
              controllers.core.routes.ActorController.capacity(id, 0),
              "fa fa-barcode",
              false));

      sideBar.addMenuItem(allocationMenu);

      sideBar.addMenuItem(
          new ClickableMenuItem(
              "core.actor.sidebar.timesheet",
              controllers.core.routes.ActorController.viewWeeklyTimesheet(id, ""),
              "fa fa-clock-o",
              currentType.equals(MenuItemType.TIMESHEET)));
    }

    return sideBar;
  }
  /**
   * Display the gantt of allocations of the actor.
   *
   * @param id the actor id
   */
  @With(CheckActorExists.class)
  @Dynamic(IMafConstants.ACTOR_VIEW_DYNAMIC_PERMISSION)
  public Result allocation(Long id) {

    // get the actor
    Actor actor = ActorDao.getActorById(id);

    // prepare the data (to order them)
    SortableCollection<DateSortableObject> sortableCollection = new SortableCollection<>();
    for (PortfolioEntryResourcePlanAllocatedActor allocatedActor :
        PortfolioEntryResourcePlanDAO.getPEPlanAllocatedActorAsListByActorAndActive(id, true)) {
      if (allocatedActor.endDate != null) {
        sortableCollection.addObject(
            new DateSortableObject(allocatedActor.endDate, allocatedActor));
      }
    }
    for (TimesheetActivityAllocatedActor allocatedActivity :
        TimesheetDao.getTimesheetActivityAllocatedActorAsListByActor(id, true)) {
      if (allocatedActivity.endDate != null) {
        sortableCollection.addObject(
            new DateSortableObject(allocatedActivity.endDate, allocatedActivity));
      }
    }

    // construct the gantt

    List<SourceItem> items = new ArrayList<SourceItem>();

    for (DateSortableObject dateSortableObject : sortableCollection.getSorted()) {

      if (dateSortableObject.getObject() instanceof PortfolioEntryResourcePlanAllocatedActor) {

        PortfolioEntryResourcePlanAllocatedActor allocatedActor =
            (PortfolioEntryResourcePlanAllocatedActor) dateSortableObject.getObject();

        // get the from date
        Date from = allocatedActor.startDate;

        // get the to date
        Date to = allocatedActor.endDate;

        // get the portfolio entry
        Long portfolioEntryId =
            allocatedActor.portfolioEntryResourcePlan.lifeCycleInstancePlannings.get(0)
                .lifeCycleInstance
                .portfolioEntry
                .id;
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(portfolioEntryId);

        String packageName =
            allocatedActor.portfolioEntryPlanningPackage != null
                ? allocatedActor.portfolioEntryPlanningPackage.getName()
                : "";

        SourceItem item = new SourceItem(portfolioEntry.getName(), packageName);

        String cssClass = null;

        if (from != null) {

          to = JqueryGantt.cleanToDate(from, to);
          cssClass = "";

        } else {

          from = to;
          cssClass = "diamond diamond-";
        }

        if (allocatedActor.isConfirmed) {
          cssClass += "success";
        } else {
          cssClass += "warning";
        }

        SourceDataValue dataValue =
            new SourceDataValue(
                controllers.core.routes.PortfolioEntryPlanningController.resources(
                        portfolioEntry.id)
                    .url(),
                null,
                null,
                null,
                null);

        item.values.add(
            new SourceValue(
                from,
                to,
                "",
                views
                    .html
                    .framework_views
                    .parts
                    .formats
                    .display_number
                    .render(allocatedActor.days, null, false)
                    .body(),
                cssClass,
                dataValue));

        items.add(item);
      }

      if (dateSortableObject.getObject() instanceof TimesheetActivityAllocatedActor) {

        TimesheetActivityAllocatedActor allocatedActivity =
            (TimesheetActivityAllocatedActor) dateSortableObject.getObject();

        // get the from date
        Date from = allocatedActivity.startDate;

        // get the to date
        Date to = allocatedActivity.endDate;

        SourceItem item = new SourceItem(allocatedActivity.timesheetActivity.getName(), "");

        String cssClass = null;

        if (from != null) {

          to = JqueryGantt.cleanToDate(from, to);
          cssClass = "";

        } else {

          from = to;
          cssClass = "diamond diamond-";
        }

        cssClass += "info";

        SourceDataValue dataValue =
            new SourceDataValue(
                controllers.core.routes.ActorController.allocationDetails(actor.id, 0, 0, false)
                    .url(),
                null,
                null,
                null,
                null);

        item.values.add(
            new SourceValue(
                from,
                to,
                "",
                views
                    .html
                    .framework_views
                    .parts
                    .formats
                    .display_number
                    .render(allocatedActivity.days, null, false)
                    .body(),
                cssClass,
                dataValue));

        items.add(item);
      }
    }

    String ganttSource = "";
    try {
      ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
      ganttSource = ow.writeValueAsString(items);
    } catch (JsonProcessingException e) {
      Logger.error(e.getMessage());
    }

    return ok(views.html.core.actor.actor_allocation.render(actor, ganttSource));
  }