org.cgiar.ccafs.ap.action.projects.ProjectCCAFSOutcomesAction.java Source code

Java tutorial

Introduction

Here is the source code for org.cgiar.ccafs.ap.action.projects.ProjectCCAFSOutcomesAction.java

Source

/*****************************************************************
 * This file is part of CCAFS Planning and Reporting Platform.
 * CCAFS P&R is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 * CCAFS P&R is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with CCAFS P&R. If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************/

package org.cgiar.ccafs.ap.action.projects;

import org.cgiar.ccafs.ap.action.BaseAction;
import org.cgiar.ccafs.ap.config.APConstants;
import org.cgiar.ccafs.ap.data.manager.HistoryManager;
import org.cgiar.ccafs.ap.data.manager.IPElementManager;
import org.cgiar.ccafs.ap.data.manager.IPIndicatorManager;
import org.cgiar.ccafs.ap.data.manager.IPProgramManager;
import org.cgiar.ccafs.ap.data.manager.ProjectManager;
import org.cgiar.ccafs.ap.data.model.Activity;
import org.cgiar.ccafs.ap.data.model.ComponentLesson;
import org.cgiar.ccafs.ap.data.model.IPElement;
import org.cgiar.ccafs.ap.data.model.IPElementType;
import org.cgiar.ccafs.ap.data.model.IPIndicator;
import org.cgiar.ccafs.ap.data.model.IPProgram;
import org.cgiar.ccafs.ap.data.model.Project;
import org.cgiar.ccafs.ap.validation.projects.ProjectCCAFSOutcomesValidator;
import org.cgiar.ccafs.utils.APConfig;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.google.inject.Inject;
import org.apache.commons.lang3.StringUtils;

/**
 * @author Hernn David Carvajal B. - CIAT/CCAFS
 * @author Hctor Fabio Tobn R. - CIAT/CCAFS
 */

public class ProjectCCAFSOutcomesAction extends BaseAction {

    private static final long serialVersionUID = 1911430786026486532L;

    // Manager
    private IPProgramManager programManager;
    private IPElementManager ipElementManager;
    private ProjectManager projectManager;
    private HistoryManager historyManager;
    private IPIndicatorManager indicatorManager;

    // Model
    private List<IPElement> midOutcomes;
    private List<IPProgram> projectFocusList;
    private Activity activity;
    private List<IPElement> midOutcomesSelected;
    private List<IPElement> previousOutputs;
    private List<IPIndicator> previousIndicators;
    private List<Integer> allYears;

    // Front-end
    private int activityID;

    private int projectID;
    private Project project;
    // Validator
    private ProjectCCAFSOutcomesValidator validator;

    @Inject
    public ProjectCCAFSOutcomesAction(APConfig config, IPProgramManager programManager,
            IPElementManager ipElementManager, ProjectManager projectManager, HistoryManager historyManager,
            IPIndicatorManager indicatorManager, ProjectCCAFSOutcomesValidator validator) {
        super(config);
        this.programManager = programManager;
        this.ipElementManager = ipElementManager;
        this.projectManager = projectManager;
        this.historyManager = historyManager;
        this.indicatorManager = indicatorManager;
        this.validator = validator;
    }

    public Activity getActivity() {
        return activity;
    }

    public int getActivityID() {
        return activityID;
    }

    public List<Integer> getAllYears() {
        return allYears;
    }

    /**
     * This method return a string with the acronym of the impact pathways to which the project can contribute.
     * The flagship programs appears only when the global region is selected.
     * 
     * @return
     */
    public String getContributingPrograms() {
        boolean isGlobalRegionSelected = projectFocusList.contains(new IPProgram(APConstants.GLOBAL_PROGRAM));
        StringBuilder programs = new StringBuilder();
        boolean hasPrevious = false;

        for (int c = 0; c < projectFocusList.size(); c++) {
            IPProgram ipProgram = projectFocusList.get(c);

            if (ipProgram.isFlagshipProgram() && !isGlobalRegionSelected) {
                continue;
            }

            if (ipProgram.getId() == APConstants.GLOBAL_PROGRAM) {
                continue;
            }

            programs.append((c > 0 && hasPrevious) ? ", " + ipProgram.getAcronym() : ipProgram.getAcronym());
            hasPrevious = true;
        }

        return programs.toString();
    }

    @Override
    public int getCurrentPlanningYear() {
        return config.getPlanningCurrentYear();
    }

    public List<IPElement> getMidOutcomeOutputs(int midOutcomeID) {
        List<IPElement> outputs = new ArrayList<>();
        IPElement midOutcome = ipElementManager.getIPElement(midOutcomeID);

        if (this.isRegionalOutcome(midOutcome)) {
            List<IPElement> mogs = new ArrayList<>();
            for (IPElement fsOutcome : midOutcome.getTranslatedOf()) {
                mogs.addAll(ipElementManager.getIPElementsByParent(fsOutcome,
                        APConstants.ELEMENT_RELATION_CONTRIBUTION));
                for (IPElement mog : mogs) {
                    if (!outputs.contains(mog)) {
                        outputs.add(mog);
                    }
                }
            }
        } else {
            outputs = ipElementManager.getIPElementsByParent(midOutcome, APConstants.ELEMENT_RELATION_CONTRIBUTION);
        }
        return outputs;
    }

    /**
     * In order to get the indicators and the mogs associated to
     * each midOutcome, we need the midOutcome identifier and the
     * identifier of the program corresponding to the midOutcome.
     * To send both values, we are going to send a composed key in
     * the map:
     * < "midOutcome.id-midoutcome.program.id", midoutcome.description >
     * 
     * @return
     */
    public Map<String, String> getMidOutcomes() {
        Map<String, String> midOutcomesMap = new TreeMap<>();

        for (IPElement midOutcome : midOutcomes) {

            // The first value of the list is the placeHolder,
            // therefore we should be omit the key concatenation
            if (midOutcome.getId() == -1) {
                midOutcomesMap.put(String.valueOf(midOutcome.getId()), midOutcome.getDescription());
                continue;
            }

            String id = String.valueOf(midOutcome.getId()) + "-" + String.valueOf(midOutcome.getProgram().getId());
            midOutcomesMap.put(id, midOutcome.getDescription());
        }

        return midOutcomesMap;
    }

    private void getMidOutcomesByIndicators() {
        for (IPIndicator indicator : project.getIndicators()) {
            IPElement midoutcome = ipElementManager.getIPElement(indicator.getOutcome().getId());
            if (!midOutcomesSelected.contains(midoutcome)) {
                String description = midoutcome.getProgram().getAcronym() + " - "
                        + this.getText("planning.activityImpactPathways.outcome2019") + ": "
                        + midoutcome.getDescription();
                midoutcome.setDescription(description);

                midOutcomesSelected.add(midoutcome);
            }
        }
    }

    private void getMidOutcomesByOutputs() {
        for (IPElement output : project.getOutputs()) {
            for (IPElement parent : output.getContributesTo()) {
                IPElement midoutcome = ipElementManager.getIPElement(parent.getId());
                if (!midOutcomesSelected.contains(midoutcome)) {
                    String description = midoutcome.getComposedId() + ": " + midoutcome.getDescription();
                    midoutcome.setDescription(description);

                    midOutcomesSelected.add(midoutcome);
                }
            }
        }
    }

    /**
     * This method is in charge of add the outcomes 2019 which correspond with the
     * project focuses chose previously.
     */
    private void getMidOutcomesByProjectFocuses() {
        boolean isGlobalProject;
        isGlobalProject = projectFocusList.contains(new IPProgram(APConstants.GLOBAL_PROGRAM));

        IPElementType midOutcomeType = new IPElementType(APConstants.ELEMENT_TYPE_OUTCOME2019);
        for (IPProgram program : projectFocusList) {

            if (!isGlobalProject && program.isFlagshipProgram()) {
                continue;
            }

            List<IPElement> elements = ipElementManager.getIPElements(program, midOutcomeType);

            for (int i = 0; i < elements.size(); i++) {
                IPElement midOutcome = elements.get(i);
                if (this.isValidMidoutcome(midOutcome)) {
                    midOutcome.setDescription(midOutcome.getComposedId() + ": " + midOutcome.getDescription());
                    midOutcomes.add(midOutcome);
                }

            }
        }
    }

    public List<IPElement> getMidOutcomesSelected() {
        return midOutcomesSelected;
    }

    public int getMidOutcomeYear() {
        return config.getMidOutcomeYear();
    }

    public int getMOGIndex(IPElement mog) {
        int index = 0;
        List<IPElement> allMOGs = ipElementManager.getIPElements(mog.getProgram(), mog.getType());

        for (int i = 0; i < allMOGs.size(); i++) {
            if (allMOGs.get(i).getId() == mog.getId()) {
                return (i + 1);
            }
        }

        return index;
    }

    public Project getProject() {
        return project;
    }

    public List<IPProgram> getProjectFocusList() {
        return projectFocusList;
    }

    public int getProjectID() {
        return projectID;
    }

    public boolean isNewProject() {
        return project.isNew(config.getCurrentPlanningStartDate());
    }

    public boolean isRegionalOutcome(IPElement outcome) {
        return !outcome.getTranslatedOf().isEmpty();
    }

    /**
     * The regional midOutcomes only can be selected if they are translation of
     * an outcome that belongs to the project focuses.
     * 
     * @param midOutcome - The element to evaluate
     * @return True if the midOutcome belongs to a flagship.
     *         True if the midOutcome is regional but is translated from an
     *         outcome that belongs to some of the project focuses.
     *         False otherwise.
     */
    private boolean isValidMidoutcome(IPElement midOutcome) {
        //
        if (!midOutcome.getTranslatedOf().isEmpty()) {
            for (IPElement parentElement : midOutcome.getTranslatedOf()) {
                if (projectFocusList.contains(parentElement.getProgram())) {
                    return true;
                }
            }
        } else {
            // Is a flagship midOutcome
            return true;
        }

        return false;
    }

    @Override
    public String next() {
        String result = this.save();
        if (result.equals(BaseAction.SUCCESS)) {
            return BaseAction.NEXT;
        } else {
            return result;
        }
    }

    @Override
    public void prepare() throws Exception {
        super.prepare();

        midOutcomes = new ArrayList<>();
        midOutcomesSelected = new ArrayList<>();
        projectID = Integer
                .parseInt(StringUtils.trim(this.getRequest().getParameter(APConstants.PROJECT_REQUEST_ID)));
        project = projectManager.getProject(projectID);

        // Get all years
        allYears = project.getAllYears();
        allYears.add(this.getMidOutcomeYear());

        // Load the project impact pathway

        // Get the programs to which the project contributes
        projectFocusList = new ArrayList<>();
        projectFocusList.addAll(programManager.getProjectFocuses(projectID, APConstants.FLAGSHIP_PROGRAM_TYPE));
        projectFocusList.addAll(programManager.getProjectFocuses(projectID, APConstants.REGION_PROGRAM_TYPE));

        // Get the project outputs from database
        project.setOutputs(ipElementManager.getProjectOutputsCcafs(projectID));

        // Get the project indicators from database
        project.setIndicators(indicatorManager.getProjectIndicators(projectID));

        // Then, we have to get all the midOutcomes that belongs to the project focuses
        this.getMidOutcomesByProjectFocuses();

        // Get all the midOutcomes selected
        this.getMidOutcomesByOutputs();

        // Get all the midOutcomes selected through the indicators
        this.getMidOutcomesByIndicators();

        this.removeOutcomesAlreadySelected();

        // Keep the activity outputs brought from the database
        previousOutputs = new ArrayList<>();
        previousOutputs.addAll(project.getOutputs());

        // Save the activity indicators brought from the database
        previousIndicators = new ArrayList<>();
        previousIndicators.addAll(project.getIndicators());

        // Getting the Project lessons for this section.
        int evaluatingYear = 0;
        if (this.getCycleName().equals(APConstants.REPORTING_SECTION)) {
            evaluatingYear = this.getCurrentReportingYear();
        } else {
            evaluatingYear = this.getCurrentPlanningYear();
        }
        ComponentLesson lessons = lessonManager.getProjectComponentLesson(projectID, this.getActionName(),
                evaluatingYear, this.getCycleName());
        this.setProjectLessons(lessons);

        super.setHistory(historyManager.getCCAFSOutcomesHistory(projectID));

        // Initializing Section Statuses:
        this.initializeProjectSectionStatuses(project, this.getCycleName());
        if (this.getCycleName().equals(APConstants.REPORTING_SECTION)) {
            this.setProjectLessonsPreview(lessonManager.getProjectComponentLesson(projectID, this.getActionName(),
                    this.getCurrentReportingYear(), APConstants.PLANNING_SECTION));
        }
        if (this.getRequest().getMethod().equalsIgnoreCase("post")) {
            // Clear out the list if it has some element
            if (project.getIndicators() != null) {
                project.getIndicators().clear();
            }

            if (project.getOutputs() != null) {
                project.getOutputs().clear();
            }
        }
    }

    private void removeOutcomesAlreadySelected() {
        for (int i = 0; i < midOutcomes.size(); i++) {
            if (midOutcomesSelected.contains(midOutcomes.get(i))) {
                midOutcomes.remove(i);
                i--;
            }
        }
    }

    @Override
    public String save() {

        if (this.hasProjectPermission("update", projectID)) {
            boolean success = true;

            if (!this.isNewProject()) {
                if (!this.isReportingCycle()) {
                    super.saveProjectLessons(projectID);
                }

            }

            // Delete the outputs removed
            for (IPElement output : previousOutputs) {
                if (!project.containsOutput(output)) {
                    boolean deleted = projectManager.deleteProjectOutput(projectID, output.getId(),
                            output.getContributesToIDs()[0], this.getCurrentUser().getId(),
                            this.getJustification());
                    if (!deleted) {
                        success = false;
                    }
                }
            }

            success = success && projectManager.saveProjectOutputs(project.getOutputs(), projectID,
                    this.getCurrentUser(), this.getJustification());

            // Delete the indicators removed
            for (IPIndicator indicator : previousIndicators) {
                if (!project.getIndicators().contains(indicator)) {
                    boolean deleted = projectManager.deleteIndicator(projectID, indicator.getId(),
                            this.getCurrentUser(), this.getJustification());
                    if (!deleted) {
                        success = false;
                    }
                }
            }

            success = success && indicatorManager.saveProjectIndicators(project.getIndicators(), projectID,
                    this.getCurrentUser(), this.getJustification());

            // Displaying user messages.
            if (success == false) {
                this.addActionError(this.getText("saving.problem"));
                return BaseAction.INPUT;
            }

            // Get the validation messages and append them to the save message
            Collection<String> messages = this.getActionMessages();
            if (!messages.isEmpty()) {
                String validationMessage = messages.iterator().next();
                // Action messages coming from the validation.
                this.setActionMessages(null);
                this.addActionWarning(this.getText("saving.saved") + validationMessage);
            } else {
                this.addActionMessage(this.getText("saving.saved"));
            }
            return SUCCESS;

        } else {
            return BaseAction.NOT_AUTHORIZED;
        }
    }

    public void setActivity(Activity activity) {
        this.activity = activity;
    }

    public void setActivityID(int activityID) {
        this.activityID = activityID;
    }

    public void setProjectID(int projectID) {
        this.projectID = projectID;
    }

    @Override
    public void validate() {
        if (save) {
            // Validating.
            validator.validate(this, project, this.getCycleName());
        }
    }

}