ParliamentDecisionFlowPageModContentFactoryImpl.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.parliament.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.PageCommandParliamentRankingConstants;
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 ParliamentDecisionFlowPageModContentFactoryImpl extends AbstractParliamentPageModContentFactoryImpl {
/** The Constant DEFAULT_YEAR. */
private static final String DEFAULT_YEAR = "2023/24";
/** The Constant YEAR_SELECTOR_LABEL. */
private static final String YEAR_SELECTOR_LABEL = "Select year";
/** 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();
setupMenuAndHeader(menuBar, panel, panelContent);
final String selectedYear = extractSelectedYear(parameters);
final Map<String, List<ViewRiksdagenCommittee>> committeeMap = loadCommitteeMap();
addYearSelector(panelContent, selectedYear);
addDecisionFlowChart(panelContent, committeeMap, selectedYear);
addDecisionSummary(panelContent, committeeMap, selectedYear);
recordPageVisit(parameters, selectedYear);
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
*/
private void setupMenuAndHeader(final MenuBar menuBar, final Panel panel, final VerticalLayout panelContent) {
getParliamentMenuItemFactory().createParliamentTopicMenu(menuBar);
CardInfoRowUtil.createPageHeader(panel, panelContent,
ParliamentPageTitleConstants.DECISION_FLOW_TITLE,
ParliamentPageTitleConstants.DECISION_FLOW_SUBTITLE,
ParliamentPageTitleConstants.DECISION_FLOW_DESC);
}
/**
* 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
*/
private void addYearSelector(final VerticalLayout panelContent, final String selectedYear) {
final ComboBox<String> yearSelector = new ComboBox<>(YEAR_SELECTOR_LABEL, createAvailableYears());
yearSelector.setWidth("200px");
yearSelector.setEmptySelectionAllowed(false);
yearSelector.setSelectedItem(selectedYear);
yearSelector.addValueChangeListener(new DecisionFlowValueChangeListener(NAME, ""));
panelContent.addComponent(yearSelector);
panelContent.setExpandRatio(yearSelector, ContentRatio.SMALL);
}
/**
* Adds the decision flow chart.
*
* @param panelContent the panel content
* @param committeeMap the committee map
* @param selectedYear the selected year
*/
private void addDecisionFlowChart(final VerticalLayout panelContent,
final Map<String, List<ViewRiksdagenCommittee>> committeeMap, final String selectedYear) {
final SankeyChart chart = decisionFlowChartManager.createAllDecisionFlow(committeeMap, selectedYear);
chart.setWidth("100%");
panelContent.addComponent(chart);
panelContent.setExpandRatio(chart, ContentRatio.LARGE);
}
/**
* Adds the decision summary.
*
* @param panelContent the panel content
* @param committeeMap the committee map
* @param selectedYear the selected year
*/
private void addDecisionSummary(final VerticalLayout panelContent,
final Map<String, List<ViewRiksdagenCommittee>> committeeMap, final String selectedYear) {
final TextArea summaryArea = decisionFlowChartManager.createCommitteeeDecisionSummary(committeeMap, selectedYear);
summaryArea.setSizeFull();
summaryArea.setReadOnly(true);
panelContent.addComponent(summaryArea);
panelContent.setExpandRatio(summaryArea, ContentRatio.SMALL_GRID);
}
/**
* Record page visit.
*
* @param parameters the parameters
* @param selectedYear the selected year
*/
private void recordPageVisit(final String parameters, final String selectedYear) {
getPageActionEventHelper().createPageEvent(
ViewAction.VISIT_PARLIAMENT_RANKING_VIEW,
ApplicationEventGroup.USER,
NAME,
parameters,
selectedYear
);
}
/**
* Matches.
*
* @param page the page
* @param parameters the parameters
* @return true, if successful
*/
@Override
public boolean matches(final String page, final String parameters) {
return PageCommandParliamentRankingConstants.COMMAND_CHARTS_DECISION_FLOW.matches(page, parameters);
}
}