DataQualityOverviewPageModContentFactoryImpl.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.admin.dataquality.pagemode;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;

import com.hack23.cia.web.impl.ui.application.views.admin.AdminViewConstants;
import com.hack23.cia.web.impl.ui.application.views.common.pagemode.AbstractPageModContentFactoryImpl;
import com.hack23.cia.web.impl.ui.application.views.common.pagemode.CardInfoRowUtil;
import com.hack23.cia.web.impl.ui.application.views.common.rows.RowUtil;
import com.hack23.cia.web.impl.ui.application.views.common.sizing.ContentRatio;
import com.hack23.cia.web.impl.ui.application.views.common.viewnames.AdminViews;
import com.jarektoro.responsivelayout.ResponsiveRow;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;

/**
 * The Class DataQualityOverviewPageModContentFactoryImpl.
 * 
 * Displays the data quality monitoring dashboard for 4 OSINT data sources.
 * 
 * NOTE: Hardcoded data values are placeholders for Phase 1.
 * Future phases will implement dynamic data retrieval from database/services.
 */
@Component
public final class DataQualityOverviewPageModContentFactoryImpl extends AbstractPageModContentFactoryImpl {

	/** The Constant NAME. */
	public static final String NAME = AdminViews.ADMIN_DATA_QUALITY_VIEW_NAME;

	/** The Constant DATA_QUALITY_MONITORING. */
	private static final String DATA_QUALITY_MONITORING = "Data Quality Monitoring";
	
	/** The Constant OVERVIEW_DESCRIPTION. */
	private static final String OVERVIEW_DESCRIPTION = "Monitor data quality metrics for 4 OSINT data sources: Riksdagen API, Election Authority, World Bank, and Financial Authority";

	/** The Constant RIKSDAGEN_API. */
	public static final String RIKSDAGEN_API = "Riksdagen API";

	/** The Constant ELECTION_AUTHORITY. */
	public static final String ELECTION_AUTHORITY = "Election Authority";

	/** The Constant WORLD_BANK. */
	public static final String WORLD_BANK = "World Bank";

	/** The Constant FINANCIAL_AUTHORITY. */
	public static final String FINANCIAL_AUTHORITY = "Financial Authority";

	/** The Constant DATA_FRESHNESS. */
	public static final String DATA_FRESHNESS = "Data Freshness";

	/** The Constant DATA_COMPLETENESS. */
	public static final String DATA_COMPLETENESS = "Data Completeness";

	/** The Constant DATA_ACCURACY. */
	public static final String DATA_ACCURACY = "Data Accuracy";

	/** The Constant ACTIVE_ALERTS. */
	public static final String ACTIVE_ALERTS = "Active Alerts";

	/**
	 * Instantiates a new data quality overview page mod content factory impl.
	 */
	public DataQualityOverviewPageModContentFactoryImpl() {
		super();
	}

	@Secured({ "ROLE_ADMIN" })
	@Override
	public Layout createContent(final String parameters, final MenuBar menuBar, final Panel panel) {
		final VerticalLayout content = createPanelContent();

		getMenuItemFactory().createMainPageMenuBar(menuBar);

		CardInfoRowUtil.createPageHeader(panel, content, DATA_QUALITY_MONITORING, AdminViewConstants.ADMIN_DATA_QUALITY, OVERVIEW_DESCRIPTION);

		final HorizontalLayout horizontalLayout = new HorizontalLayout();
		horizontalLayout.setSizeFull();
		horizontalLayout.addStyleName("v-layout-content-overview-panel-level1");

		content.addComponent(horizontalLayout);
		content.setExpandRatio(horizontalLayout, ContentRatio.LARGE);

		// Create data source status section
		createDataSourceStatusSection(horizontalLayout);

		final VerticalLayout metricsLayout = new VerticalLayout();
		metricsLayout.setSizeFull();
		metricsLayout.addStyleName("v-layout-content-overview-panel-level2");

		content.addComponent(metricsLayout);
		content.setExpandRatio(metricsLayout, ContentRatio.LARGE);

		final ResponsiveRow grid = RowUtil.createGridLayout(metricsLayout);

		// Create data quality metrics cards
		createDataQualityMetricsCards(grid);

		return content;
	}

	/**
	 * Creates the data source status section.
	 *
	 * @param layout the layout
	 */
	private void createDataSourceStatusSection(final HorizontalLayout layout) {
		final VerticalLayout statusLayout = new VerticalLayout();
		statusLayout.setSizeFull();
		statusLayout.setSpacing(true);
		statusLayout.setMargin(true);

		final Label titleLabel = new Label("Data Source Status");
		titleLabel.addStyleName("h2");
		statusLayout.addComponent(titleLabel);

		// Riksdagen API status
		createDataSourceStatusCard(statusLayout, RIKSDAGEN_API, "Swedish Parliament", VaadinIcons.INSTITUTION, "✓ Active", "Last update: 2 hours ago");

		// Election Authority status
		createDataSourceStatusCard(statusLayout, ELECTION_AUTHORITY, "Valmyndigheten", VaadinIcons.CHECK_SQUARE, "✓ Active", "Last update: 12 hours ago");

		// World Bank status
		createDataSourceStatusCard(statusLayout, WORLD_BANK, "Open Data", VaadinIcons.GLOBE, "✓ Active", "Last update: 24 hours ago");

		// Financial Authority status
		createDataSourceStatusCard(statusLayout, FINANCIAL_AUTHORITY, "ESV", VaadinIcons.MONEY, "✓ Active", "Last update: 6 hours ago");

		layout.addComponent(statusLayout);
	}

	/**
	 * Creates a data source status card.
	 *
	 * @param layout the layout
	 * @param name the name
	 * @param description the description
	 * @param icon the icon
	 * @param status the status
	 * @param lastUpdate the last update
	 */
	private void createDataSourceStatusCard(final VerticalLayout layout, final String name, 
			final String description, final VaadinIcons icon, final String status, final String lastUpdate) {
		final HorizontalLayout cardLayout = new HorizontalLayout();
		cardLayout.setWidth("100%");
		cardLayout.setSpacing(true);
		cardLayout.addStyleName("data-source-card");

		// Use icon directly without HTML rendering
		final Label iconLabel = new Label("");
		iconLabel.addStyleName("data-source-icon");
		iconLabel.setIcon(icon);
		cardLayout.addComponent(iconLabel);

		final VerticalLayout infoLayout = new VerticalLayout();
		infoLayout.setSpacing(false);
		infoLayout.setMargin(false);

		final Label nameLabel = new Label(name);
		nameLabel.addStyleName("h3");
		infoLayout.addComponent(nameLabel);

		final Label descLabel = new Label(description);
		descLabel.addStyleName("data-source-description");
		infoLayout.addComponent(descLabel);

		final Label statusLabel = new Label(status);
		statusLabel.addStyleName("data-source-status-active");
		infoLayout.addComponent(statusLabel);

		final Label updateLabel = new Label(lastUpdate);
		updateLabel.addStyleName("data-source-last-update");
		infoLayout.addComponent(updateLabel);

		cardLayout.addComponent(infoLayout);
		cardLayout.setExpandRatio(infoLayout, 1.0f);

		layout.addComponent(cardLayout);
	}

	/**
	 * Creates the data quality metrics cards.
	 *
	 * @param grid the grid
	 */
	private void createDataQualityMetricsCards(final ResponsiveRow grid) {
		// Data Freshness Card
		final VerticalLayout freshnessCard = new VerticalLayout();
		freshnessCard.setSpacing(true);
		freshnessCard.setMargin(true);
		freshnessCard.addStyleName("metric-card");

		final Label freshnessTitle = new Label(DATA_FRESHNESS);
		freshnessTitle.addStyleName("h3");
		freshnessCard.addComponent(freshnessTitle);

		final Label freshnessValue = new Label("98.5%");
		freshnessValue.addStyleName("metric-value");
		freshnessCard.addComponent(freshnessValue);

		final Label freshnessDesc = new Label("Data updated within 24 hours");
		freshnessDesc.addStyleName("metric-description");
		freshnessCard.addComponent(freshnessDesc);

		RowUtil.createRowComponent(grid, freshnessCard, "Data Freshness Metric");

		// Completeness Card
		final VerticalLayout completenessCard = new VerticalLayout();
		completenessCard.setSpacing(true);
		completenessCard.setMargin(true);
		completenessCard.addStyleName("metric-card");

		final Label completenessTitle = new Label(DATA_COMPLETENESS);
		completenessTitle.addStyleName("h3");
		completenessCard.addComponent(completenessTitle);

		final Label completenessValue = new Label("96.2%");
		completenessValue.addStyleName("metric-value");
		completenessCard.addComponent(completenessValue);

		final Label completenessDesc = new Label("Expected records present");
		completenessDesc.addStyleName("metric-description");
		completenessCard.addComponent(completenessDesc);

		RowUtil.createRowComponent(grid, completenessCard, "Data Completeness Metric");

		// Accuracy Card
		final VerticalLayout accuracyCard = new VerticalLayout();
		accuracyCard.setSpacing(true);
		accuracyCard.setMargin(true);
		accuracyCard.addStyleName("metric-card");

		final Label accuracyTitle = new Label(DATA_ACCURACY);
		accuracyTitle.addStyleName("h3");
		accuracyCard.addComponent(accuracyTitle);

		final Label accuracyValue = new Label("99.1%");
		accuracyValue.addStyleName("metric-value");
		accuracyCard.addComponent(accuracyValue);

		final Label accuracyDesc = new Label("Validation checks passed");
		accuracyDesc.addStyleName("metric-description");
		accuracyCard.addComponent(accuracyDesc);

		RowUtil.createRowComponent(grid, accuracyCard, "Data Accuracy Metric");

		// Alerts Card
		final VerticalLayout alertsCard = new VerticalLayout();
		alertsCard.setSpacing(true);
		alertsCard.setMargin(true);
		alertsCard.addStyleName("metric-card");

		final Label alertsTitle = new Label(ACTIVE_ALERTS);
		alertsTitle.addStyleName("h3");
		alertsCard.addComponent(alertsTitle);

		final Label alertsValue = new Label("2");
		alertsValue.addStyleName("metric-value");
		alertsCard.addComponent(alertsValue);

		final Label alertsDesc = new Label("Quality issues detected");
		alertsDesc.addStyleName("metric-description");
		alertsCard.addComponent(alertsDesc);

		RowUtil.createRowComponent(grid, alertsCard, "Active Alerts Metric");
	}

	@Override
	public boolean matches(final String page, final String parameters) {
		return NAME.equals(page);
	}

	@Override
	public boolean validReference(final String parameters) {
		return true;
	}

}