PoliticianLeaderboardUtil.java
- package com.hack23.cia.web.impl.ui.application.views.common.pagemode;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.stream.Collectors;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import com.hack23.cia.model.internal.application.data.ministry.impl.ViewRiksdagenGovermentRoleMember;
- import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPolitician;
- import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPoliticianBallotSummary;
- import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPoliticianExperienceSummary;
- import com.hack23.cia.service.external.esv.api.GovernmentBodyAnnualOutcomeSummary;
- import com.hack23.cia.service.external.esv.api.GovernmentBodyAnnualSummary;
- import com.hack23.cia.web.impl.ui.application.views.common.pagelinks.api.PageLinkFactory;
- import com.vaadin.icons.VaadinIcons;
- import com.vaadin.ui.VerticalLayout;
- /**
- * The Class PoliticianLeaderboardUtil.
- */
- @Service
- public class PoliticianLeaderboardUtil extends CardInfoRowUtil {
- /** The page link factory. */
- @Autowired
- public PageLinkFactory pageLinkFactory;
- /**
- * Instantiates a new politician leaderboard util.
- */
- public PoliticianLeaderboardUtil() {
- }
- /**
- * Adds the political analysis comment.
- *
- * @param layout the layout
- * @param experienceSummary the experience summary
- */
- public final void addPoliticalAnalysisComment(final VerticalLayout layout,
- final ViewRiksdagenPoliticianExperienceSummary experienceSummary) {
- // Split the analysis points and create a bullet list
- final String[] analysisPoints = experienceSummary.getPoliticalAnalysisComment().split("\\s*\\|\\|\\s*");
- final StringBuilder analys=new StringBuilder();
- for (final String point : analysisPoints) {
- if (StringUtils.isNotBlank(point)) {
- analys.append(" • ").append(point);
- }
- }
- // Political Analysis Comment
- if (StringUtils.isNotBlank(experienceSummary.getPoliticalAnalysisComment())) {
- layout.addComponent(createInfoRow("Analysis:",
- analys.toString(),
- VaadinIcons.COMMENT,
- "Political career analysis"));
- }
- }
- /**
- * Adds the knowledge areas.
- *
- * @param layout the layout
- * @param experienceSummary the experience summary
- */
- public final void addKnowledgeAreas(final VerticalLayout layout, final ViewRiksdagenPoliticianExperienceSummary experienceSummary) {
- if (experienceSummary.getKnowledgeAreas() != null && !experienceSummary.getKnowledgeAreas().isEmpty()) {
- final String topAreas = buildTopString(
- experienceSummary.getKnowledgeAreas(),
- ka -> ka.getArea(),
- ka -> ka.getWeightedExp()
- );
- if (!topAreas.isEmpty()) {
- layout.addComponent(createInfoRow("Top Knowledge Areas:", topAreas, VaadinIcons.BOOK, "Key expertise"));
- }
- }
- }
- /**
- * Adds the top roles.
- *
- * @param layout the layout
- * @param experienceSummary the experience summary
- */
- public final void addTopRoles(final VerticalLayout layout, final ViewRiksdagenPoliticianExperienceSummary experienceSummary) {
- if (experienceSummary.getRoles() != null && !experienceSummary.getRoles().isEmpty()) {
- final String topRoles = buildTopString(
- experienceSummary.getRoles(),
- role -> role.getRole(),
- role -> role.getWeightedExp()
- );
- if (!topRoles.isEmpty()) {
- layout.addComponent(createInfoRow("Top Roles:", topRoles, VaadinIcons.STAR, "Most significant roles")); // Changed from CROWN to STAR
- }
- }
- }
- /**
- * Adds the experience metrics.
- *
- * @param layout the layout
- * @param experienceSummary the experience summary
- */
- public final void addExperienceMetrics(final VerticalLayout layout, final ViewRiksdagenPoliticianExperienceSummary experienceSummary) {
- if (experienceSummary != null) {
- // Career Overview
- layout.addComponent(createInfoRow("Career Phase:",
- experienceSummary.getCareerPhase().toString().replace("_", " "),
- VaadinIcons.CALENDAR_CLOCK,
- "Current career stage"));
- // Experience Level
- layout.addComponent(createInfoRow("Experience Level:",
- experienceSummary.getExperienceLevel().toString().replace("_", " "),
- VaadinIcons.CHART_TIMELINE,
- "Overall political experience classification"));
- // Leadership Profile
- layout.addComponent(createInfoRow("Leadership Role:",
- experienceSummary.getLeadershipProfile().toString().replace("_", " "),
- VaadinIcons.USER_STAR,
- "Leadership experience level"));
- // Specialization
- layout.addComponent(createInfoRow("Expertise:",
- experienceSummary.getSpecializationLevel().toString().replace("_", " "),
- VaadinIcons.SPECIALIST,
- "Area of specialization"));
- }
- }
- /**
- * Adds the legislative metrics.
- *
- * @param layout the layout
- * @param politician the politician
- */
- public final void addLegislativeMetrics(final VerticalLayout layout, final ViewRiksdagenPolitician politician) {
- layout.addComponent(createInfoRow("Documents/Year:", String.format(Locale.ENGLISH,"%.1f", politician.getAverageDocsPerYear()),
- VaadinIcons.FILE_TEXT, "Average documents per year"));
- layout.addComponent(createInfoRow("Individual Motions:", String.valueOf(politician.getIndividualMotions()),
- VaadinIcons.USER, "Personal motions submitted"));
- layout.addComponent(createInfoRow("Party Motions:", String.valueOf(politician.getPartyMotions()),
- VaadinIcons.GROUP, "Party-based motions"));
- layout.addComponent(createInfoRow("Committee Motions:", String.valueOf(politician.getCommitteeMotions()),
- VaadinIcons.GROUP, "Committee-based motions"));
- layout.addComponent(createInfoRow("Document Impact:", politician.getDocActivityProfile(), VaadinIcons.CHART_3D,
- "Legislative influence assessment"));
- }
- /**
- * Adds the party alignment metrics.
- *
- * @param layout the layout
- * @param politician the politician
- * @param ballotSummary the ballot summary
- */
- public final void addPartyAlignmentMetrics(final VerticalLayout layout, final ViewRiksdagenPolitician politician,
- final ViewRiksdagenPoliticianBallotSummary ballotSummary) {
- layout.addComponent(createInfoRow("Party Loyalty:", String.format(Locale.ENGLISH,"%.1f%%", ballotSummary != null ? ballotSummary.getLoyaltyRate() : 0.0),
- VaadinIcons.GROUP, "Party line adherence"));
- layout.addComponent(createInfoRow("Independence Rate:", String.format(Locale.ENGLISH,"%.1f%%", ballotSummary != null ? ballotSummary.getRebelRate() : 0.0),
- VaadinIcons.RANDOM, "Votes against party line"));
- layout.addComponent(createInfoRow("Cross-Party Collaboration:",
- String.format(Locale.ENGLISH,"%.1f%%", politician.getCollaborationPercentage()), VaadinIcons.CONNECT,
- "Inter-party cooperation"));
- layout.addComponent(createInfoRow("Multi-Party Motions:", String.valueOf(politician.getMultiPartyMotions()),
- VaadinIcons.USERS, "Cross-party legislative initiatives"));
- }
- /**
- * Adds the parliamentary performance metrics.
- *
- * @param layout the layout
- * @param politician the politician
- * @param ballotSummary the ballot summary
- */
- public final void addParliamentaryPerformanceMetrics(final VerticalLayout layout, final ViewRiksdagenPolitician politician,
- final ViewRiksdagenPoliticianBallotSummary ballotSummary) {
- layout.addComponent(
- createInfoRow("Attendance Rate:",
- String.format(Locale.ENGLISH, "%.1f%%", 100 - (ballotSummary != null ? ballotSummary.getAbsenceRate() : 0.0)),
- VaadinIcons.USER_CHECK, "Session attendance rate"));
- layout.addComponent(createInfoRow("Voting Success:",
- String.format(Locale.ENGLISH, "%.1f%%", ballotSummary != null ? ballotSummary.getSuccessRate() : 0.0),
- VaadinIcons.TROPHY, "Votes on winning side"));
- layout.addComponent(createInfoRow("Activity Level:", politician.getDocActivityLevel(), VaadinIcons.CHART_LINE,
- "Overall engagement level"));
- layout.addComponent(createInfoRow("Analysis Comment:",
- String.valueOf(ballotSummary != null ? ballotSummary.getAnalysisComment() : 0), VaadinIcons.USER_CARD,
- "Analysis Comment"));
- }
- /**
- * Adds the ministry role summary.
- *
- * @param cardLayout the card layout
- * @param govMember the gov member
- * @param governmentBodyByMinistry the government body by ministry
- * @param reportByMinistry the report by ministry
- */
- public final void addMinistryRoleSummary(final VerticalLayout cardLayout,
- final ViewRiksdagenGovermentRoleMember govMember,
- final Map<String, List<GovernmentBodyAnnualSummary>> governmentBodyByMinistry,
- final Map<String, List<GovernmentBodyAnnualOutcomeSummary>> reportByMinistry) {
- cardLayout.addComponent(pageLinkFactory.addMinistryPageLink(govMember.getDetail()));
- final List<GovernmentBodyAnnualSummary> ministryBodies = governmentBodyByMinistry.get(govMember.getDetail());
- if (ministryBodies == null || ministryBodies.isEmpty()) {
- return;
- }
- final int totalHeadCount = ministryBodies.stream().mapToInt(GovernmentBodyAnnualSummary::getAnnualWorkHeadCount)
- .sum();
- final int bodyCount = ministryBodies.size();
- cardLayout.addComponent(createMetricRow(VaadinIcons.GROUP,
- pageLinkFactory.addMinistryGovermentBodiesPageLink(govMember.getDetail()),
- "Number of government bodies", String.valueOf(bodyCount)));
- cardLayout.addComponent(createMetricRow(VaadinIcons.USER,
- pageLinkFactory.addMinistryGovermentBodiesHeadcountPageLink(govMember.getDetail()),
- "Total headcount of government bodies", String.valueOf(totalHeadCount)));
- final List<GovernmentBodyAnnualOutcomeSummary> outcomeSummaries = reportByMinistry.get(govMember.getDetail());
- double currentYearIncome = 0;
- double currentYearSpending = 0;
- final int CURRENT_YEAR = 2024;
- final String INKOMSTTITELGRUPPSNAMN = "Inkomsttitelgruppsnamn";
- final String EXPENDITURE_GROUP_NAME = "Utgiftsområdesnamn";
- if (outcomeSummaries != null) {
- final Map<Integer, Double> annualIncome = outcomeSummaries.stream()
- .filter(t -> t.getDescriptionFields().get(INKOMSTTITELGRUPPSNAMN) != null)
- .collect(Collectors.groupingBy(GovernmentBodyAnnualOutcomeSummary::getYear,
- Collectors.summingDouble(GovernmentBodyAnnualOutcomeSummary::getYearTotal)));
- final Map<Integer, Double> annualSpending = outcomeSummaries.stream()
- .filter(t -> t.getDescriptionFields().get(EXPENDITURE_GROUP_NAME) != null)
- .collect(Collectors.groupingBy(GovernmentBodyAnnualOutcomeSummary::getYear,
- Collectors.summingDouble(GovernmentBodyAnnualOutcomeSummary::getYearTotal)));
- if (annualIncome.get(CURRENT_YEAR) != null) {
- currentYearIncome = annualIncome.get(CURRENT_YEAR) / 1000;
- }
- if (annualSpending.get(CURRENT_YEAR) != null) {
- currentYearSpending = annualSpending.get(CURRENT_YEAR) / 1000;
- }
- }
- final String incomeStr = String.format(Locale.ENGLISH, "%.2f B SEK", currentYearIncome);
- cardLayout.addComponent(createMetricRow(VaadinIcons.ARROW_UP,
- pageLinkFactory.addMinistryGovermentBodiesIncomePageLink(govMember.getDetail()),
- "Yearly Income (B SEK)", incomeStr));
- final String spendingStr = String.format(Locale.ENGLISH, "%.2f B SEK", currentYearSpending);
- cardLayout.addComponent(createMetricRow(VaadinIcons.ARROW_DOWN,
- pageLinkFactory.addMinistrGovermentBodiesSpendingPageLink(govMember.getDetail()),
- "Yearly Spending (B SEK)", spendingStr));
- }
- /**
- * Builds the top string.
- *
- * @param <T> the generic type
- * @param items the items
- * @param nameFunction the name function
- * @param weightFunction the weight function
- * @return the string
- */
- private <T> String buildTopString(final List<T> items,
- final java.util.function.Function<T, String> nameFunction,
- final java.util.function.Function<T, Long> weightFunction) {
- return items.stream()
- .filter(i -> nameFunction.apply(i) != null && !"Other".equals(nameFunction.apply(i)))
- .sorted((o1, o2) -> weightFunction.apply(o2).compareTo(weightFunction.apply(o1)))
- .limit(3)
- .map(nameFunction)
- .collect(Collectors.joining(", "));
- }
- }