CommitteeDecisionFlowPageModContentFactoryImpl.java
/*
* Copyright 2010-2025 James Pether Sörling
*
* Licensed 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.
*
* $Id$
* $HeadURL$
*/
package com.hack23.cia.web.impl.ui.application.views.user.committee.pagemode;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;
import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenCommittee;
import com.hack23.cia.model.internal.application.system.impl.ApplicationEventGroup;
import com.hack23.cia.web.impl.ui.application.action.ViewAction;
import com.hack23.cia.web.impl.ui.application.views.common.chartfactory.api.DecisionFlowChartManager;
import com.hack23.cia.web.impl.ui.application.views.common.menufactory.api.pagecommands.PageCommandCommitteeConstants;
import com.hack23.cia.web.impl.ui.application.views.common.pagemode.CardInfoRowUtil;
import com.hack23.cia.web.impl.ui.application.views.common.sizing.ContentRatio;
import com.hack23.cia.web.impl.ui.application.views.pageclicklistener.DecisionFlowValueChangeListener;
import com.hack23.cia.web.widgets.charts.SankeyChart;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Layout;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.VerticalLayout;
/**
* The Class ParliamentDecisionFlowPageModContentFactoryImpl.
*/
@Component
public final class CommitteeDecisionFlowPageModContentFactoryImpl extends AbstractCommitteePageModContentFactoryImpl {
/** The Constant DEFAULT_YEAR. */
private static final String DEFAULT_YEAR = "2023/24";
/** The decision flow chart manager. */
@Autowired
private DecisionFlowChartManager decisionFlowChartManager;
/**
* Creates the content.
*
* @param parameters the parameters
* @param menuBar the menu bar
* @param panel the panel
* @return the layout
*/
@Secured({ "ROLE_ANONYMOUS", "ROLE_USER", "ROLE_ADMIN" })
@Override
public Layout createContent(final String parameters, final MenuBar menuBar, final Panel panel) {
final VerticalLayout panelContent = createPanelContent();
final String pageId = getPageId(parameters);
final ViewRiksdagenCommittee committee = getItem(parameters);
setupMenuAndHeader(menuBar, panel, panelContent, pageId, committee);
final String selectedYear = extractSelectedYear(parameters);
final Map<String, List<ViewRiksdagenCommittee>> committeeMap = loadCommitteeMap();
addYearSelector(panelContent, selectedYear, pageId);
addDecisionFlowChart(panelContent, committee, committeeMap, selectedYear);
addDecisionSummary(panelContent, committee, selectedYear);
recordPageVisit(parameters, pageId);
return panelContent;
}
/**
* Creates list of available years for selection.
* Goes from 2010/11 up to (currentYear+1)/(currentYear+2).
*
* @return Unmodifiable list of year strings in format "YYYY/YY"
*/
private static List<String> createAvailableYears() {
final int currentYear = LocalDate.now((ZoneOffset.UTC)).getYear();
return IntStream.rangeClosed(2010, currentYear + 1)
.mapToObj(year -> String.format(Locale.ENGLISH,"%d/%02d", year, (year + 1) % 100))
.sorted(Comparator.reverseOrder()) // Most recent years first
.collect(Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList
));
}
/**
* Setup menu and header.
*
* @param menuBar the menu bar
* @param panel the panel
* @param panelContent the panel content
* @param pageId the page id
* @param committee the committee
*/
private void setupMenuAndHeader(final MenuBar menuBar, final Panel panel, final VerticalLayout panelContent,
final String pageId, final ViewRiksdagenCommittee committee) {
getCommitteeMenuItemFactory().createCommitteeeMenuBar(menuBar, pageId);
CardInfoRowUtil.createPageHeader(panel, panelContent,
CommitteeViewConstants.DF_TITLE_HEADER + committee.getEmbeddedId().getDetail(),
CommitteeViewConstants.DF_TITLE,
CommitteeViewConstants.DF_DESCRIPTION
);
}
/**
* Extract selected year.
*
* @param parameters the parameters
* @return the string
*/
private String extractSelectedYear(final String parameters) {
if (parameters != null && parameters.contains("[") && parameters.contains("]")) {
return parameters.substring(
parameters.indexOf('[') + 1,
parameters.lastIndexOf(']')
);
}
return DEFAULT_YEAR;
}
/**
* Load committee map.
*
* @return the map
*/
private Map<String, List<ViewRiksdagenCommittee>> loadCommitteeMap() {
return getApplicationManager()
.getDataContainer(ViewRiksdagenCommittee.class)
.getAll()
.stream()
.collect(Collectors.groupingBy(
committee -> committee.getEmbeddedId().getOrgCode().toUpperCase(Locale.ENGLISH)
));
}
/**
* Adds the year selector.
*
* @param panelContent the panel content
* @param selectedYear the selected year
* @param pageId the page id
*/
private void addYearSelector(final VerticalLayout panelContent, final String selectedYear, final String pageId) {
final ComboBox<String> yearSelector = new ComboBox<>(CommitteeViewConstants.DF_YEAR_SELECTOR, createAvailableYears());
yearSelector.setWidth("200px");
yearSelector.setEmptySelectionAllowed(false);
yearSelector.setSelectedItem(selectedYear);
yearSelector.addValueChangeListener(new DecisionFlowValueChangeListener(NAME, pageId));
panelContent.addComponent(yearSelector);
panelContent.setExpandRatio(yearSelector, ContentRatio.SMALL2);
}
/**
* Adds the decision flow chart.
*
* @param panelContent the panel content
* @param committee the committee
* @param committeeMap the committee map
* @param selectedYear the selected year
*/
private void addDecisionFlowChart(final VerticalLayout panelContent, final ViewRiksdagenCommittee committee,
final Map<String, List<ViewRiksdagenCommittee>> committeeMap, final String selectedYear) {
final SankeyChart chart = decisionFlowChartManager.createCommitteeDecisionFlow(
committee, committeeMap, selectedYear
);
chart.setWidth("100%");
panelContent.addComponent(chart);
panelContent.setExpandRatio(chart, ContentRatio.LARGE);
}
/**
* Adds the decision summary.
*
* @param panelContent the panel content
* @param committee the committee
* @param selectedYear the selected year
*/
private void addDecisionSummary(final VerticalLayout panelContent,
final ViewRiksdagenCommittee committee, final String selectedYear) {
final TextArea summaryArea = decisionFlowChartManager.createCommitteeeDecisionSummary(
committee, selectedYear
);
summaryArea.setSizeFull();
summaryArea.setReadOnly(true);
panelContent.addComponent(summaryArea);
panelContent.setExpandRatio(summaryArea, ContentRatio.SMALL_GRID);
}
/**
* Record page visit.
*
* @param parameters the parameters
* @param pageId the page id
*/
private void recordPageVisit(final String parameters, final String pageId) {
getPageActionEventHelper().createPageEvent(
ViewAction.VISIT_COMMITTEE_VIEW,
ApplicationEventGroup.USER,
NAME,
parameters,
pageId
);
}
/**
* Matches.
*
* @param page the page
* @param parameters the parameters
* @return true, if successful
*/
@Override
public boolean matches(final String page, final String parameters) {
return PageCommandCommitteeConstants.COMMAND_CHARTS_DECISION_FLOW.matches(page, parameters);
}
}