Java tutorial
/******************************************************************************* * SORMAS - Surveillance Outbreak Response Management & Analysis System * Copyright 2016-2018 Helmholtz-Zentrum fr Infektionsforschung GmbH (HZI) * * This program 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. * * This program 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 this program. If not, see <https://www.gnu.org/licenses/>. *******************************************************************************/ package de.symeda.sormas.ui.dashboard.contacts; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.vaadin.icons.VaadinIcons; import com.vaadin.shared.ui.ContentMode; import com.vaadin.ui.CssLayout; import com.vaadin.ui.Label; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.DiseaseHelper; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.contact.ContactClassification; import de.symeda.sormas.api.contact.ContactReferenceDto; import de.symeda.sormas.api.contact.ContactStatus; import de.symeda.sormas.api.contact.DashboardContactDto; import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.Descriptions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.visit.DashboardVisitDto; import de.symeda.sormas.api.visit.VisitFacade; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.ui.dashboard.DashboardDataProvider; import de.symeda.sormas.ui.dashboard.statistics.AbstractDashboardStatisticsComponent; import de.symeda.sormas.ui.dashboard.statistics.CountElementStyle; import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsCountElement; import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsDiseaseElement; import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsGraphicalGrowthElement; import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsPercentageElement; import de.symeda.sormas.ui.dashboard.statistics.DashboardStatisticsSubComponent; import de.symeda.sormas.ui.utils.CssStyles; @SuppressWarnings("serial") public class ContactsDashboardStatisticsComponent extends AbstractDashboardStatisticsComponent { // "All Contacts" elements private CssLayout allContactsCountLayout; private DashboardStatisticsCountElement contactClassificationUnconfirmed; private DashboardStatisticsCountElement contactClassificationConfirmed; private DashboardStatisticsCountElement contactClassificationNotAContact; private DashboardStatisticsCountElement newContacts; private DashboardStatisticsCountElement symptomaticContacts; private DashboardStatisticsPercentageElement contactClassificationUnconfirmedLarge; private DashboardStatisticsPercentageElement contactClassificationConfirmedLarge; private DashboardStatisticsPercentageElement contactClassificationNotAContactLarge; private DashboardStatisticsPercentageElement newContactsLarge; private DashboardStatisticsPercentageElement symptomaticContactsLarge; // "Follow-up Status" elements private DashboardStatisticsPercentageElement underFollowUp; private DashboardStatisticsPercentageElement followUpCompleted; private DashboardStatisticsPercentageElement followUpCanceled; private DashboardStatisticsPercentageElement lostToFollowUp; private DashboardStatisticsPercentageElement contactStatusConverted; // "Follow-up Situation" elements private DashboardStatisticsCountElement cooperativeContacts; private DashboardStatisticsCountElement uncooperativeContacts; private DashboardStatisticsCountElement unavailableContacts; private DashboardStatisticsCountElement neverVisitedContacts; private DashboardStatisticsCountElement missedVisitsOneDay; private DashboardStatisticsCountElement missedVisitsTwoDays; private DashboardStatisticsCountElement missedVisitsThreeDays; private DashboardStatisticsCountElement missedVisitsGtThreeDays; // "Follow-Up Visits" elements private DashboardStatisticsGraphicalGrowthElement missedVisits; private DashboardStatisticsGraphicalGrowthElement unavailableVisits; private DashboardStatisticsGraphicalGrowthElement uncooperativeVisits; private DashboardStatisticsGraphicalGrowthElement cooperativeVisits; public ContactsDashboardStatisticsComponent(DashboardDataProvider dashboardDataProvider) { super(dashboardDataProvider); } @Override protected void addFirstComponent() { firstComponent = new DashboardStatisticsSubComponent(); // Header firstComponent.addHeader(I18nProperties.getString(Strings.headingAllContacts), null, true); // Content firstComponent.addMainContent(); allContactsCountLayout = firstComponent.createCountLayout(true); contactClassificationUnconfirmed = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardUnconfirmed), CountElementStyle.MINOR); contactClassificationConfirmed = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardConfirmed), CountElementStyle.PRIMARY); contactClassificationNotAContact = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardNotAContact), CountElementStyle.POSITIVE); newContacts = new DashboardStatisticsCountElement(I18nProperties.getCaption(Captions.dashboardNew), CountElementStyle.NEUTRAL); symptomaticContacts = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardSymptomatic), CountElementStyle.CRITICAL); firstComponent.addComponentToCountLayout(allContactsCountLayout, contactClassificationUnconfirmed); firstComponent.addComponentToCountLayout(allContactsCountLayout, contactClassificationConfirmed); firstComponent.addComponentToCountLayout(allContactsCountLayout, contactClassificationNotAContact); firstComponent.addComponentToCountLayout(allContactsCountLayout, newContacts); firstComponent.addComponentToCountLayout(allContactsCountLayout, symptomaticContacts); firstComponent.addComponentToContent(allContactsCountLayout); contactClassificationUnconfirmedLarge = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardUnconfirmed), CssStyles.SVG_FILL_MINOR); contactClassificationConfirmedLarge = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardConfirmed), CssStyles.SVG_FILL_CRITICAL); contactClassificationNotAContactLarge = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardNotAContact), CssStyles.SVG_FILL_POSITIVE); newContactsLarge = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardNew), CssStyles.SVG_FILL_NEUTRAL); symptomaticContactsLarge = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardSymptomatic), CssStyles.SVG_FILL_CRITICAL); subComponentsLayout.addComponent(firstComponent, FIRST_LOC); } @Override protected void updateFirstComponent(int visibleDiseasesCount) { List<DashboardContactDto> contacts = dashboardDataProvider.getContacts(); List<DashboardContactDto> previousContacts = dashboardDataProvider.getPreviousContacts(); int contactsCount = contacts.size(); firstComponent.updateCountLabel(contactsCount); int newContactsCount = (int) contacts.stream() .filter(c -> c.getReportDate().after(dashboardDataProvider.getFromDate()) || c.getReportDate().equals(dashboardDataProvider.getFromDate())) .count(); int newContactsPercentage = contactsCount == 0 ? 0 : (int) ((newContactsCount * 100.0f) / contactsCount); int symptomaticContactsCount = (int) contacts.stream().filter(c -> c.isSymptomatic()).count(); int symptomaticContactsPercentage = contactsCount == 0 ? 0 : (int) ((symptomaticContactsCount * 100.0f) / contactsCount); int contactClassificationUnconfirmedCount = (int) contacts.stream() .filter(c -> c.getContactClassification() == ContactClassification.UNCONFIRMED).count(); int contactClassificationUnconfirmedPercentage = contactsCount == 0 ? 0 : (int) ((contactClassificationUnconfirmedCount * 100.0f) / contactsCount); int contactClassificationConfirmedCount = (int) contacts.stream() .filter(c -> c.getContactClassification() == ContactClassification.CONFIRMED).count(); int contactClassificationConfirmedPercentage = contactsCount == 0 ? 0 : (int) ((contactClassificationConfirmedCount * 100.0f) / contactsCount); int contactClassificationNotAContactCount = (int) contacts.stream() .filter(c -> c.getContactClassification() == ContactClassification.NO_CONTACT).count(); int contactClassificationNotAContactPercentage = contactsCount == 0 ? 0 : (int) ((contactClassificationNotAContactCount * 100.0f) / contactsCount); // Remove and re-create content layout if the disease filter has been applied or set to null if (currentDisease == null && previousDisease != null) { firstComponent.removeAllComponentsFromContent(); firstComponent.addComponentToContent(allContactsCountLayout); } else if (currentDisease != null && previousDisease == null) { firstComponent.removeAllComponentsFromContent(); firstComponent.addComponentToContent(contactClassificationUnconfirmedLarge); firstComponent.addComponentToContent(contactClassificationConfirmedLarge); firstComponent.addComponentToContent(contactClassificationNotAContactLarge); firstComponent.addComponentToContent(newContactsLarge); firstComponent.addComponentToContent(symptomaticContactsLarge); } if (currentDisease == null) { // Remove all children of the content layout firstComponent.removeAllComponentsFromContent(); firstComponent.addComponentToContent(allContactsCountLayout); contactClassificationUnconfirmed.updateCountLabel(contactClassificationUnconfirmedCount + " (" + contactClassificationUnconfirmedPercentage + " %)"); contactClassificationConfirmed.updateCountLabel( contactClassificationConfirmedCount + " (" + contactClassificationConfirmedPercentage + " %)"); contactClassificationNotAContact.updateCountLabel(contactClassificationNotAContactCount + " (" + contactClassificationNotAContactPercentage + " %)"); newContacts.updateCountLabel(newContactsCount); symptomaticContacts .updateCountLabel(symptomaticContactsCount + " (" + symptomaticContactsPercentage + " %)"); // Create a map with all diseases as keys and their respective case counts as values Map<Disease, Integer> diseaseMap = new TreeMap<Disease, Integer>(); for (Disease disease : FacadeProvider.getDiseaseConfigurationFacade().getAllDiseasesWithFollowUp()) { diseaseMap.put(disease, (int) contacts.stream().filter(c -> c.getDisease() == disease).count()); } // Create a list from this map that sorts the entries by case counts List<Map.Entry<Disease, Integer>> sortedDiseaseList = createSortedDiseaseList(diseaseMap); // Create a new StatisticsDiseaseElement for every disease, automatically sorting them by case count for (int i = 0; i < visibleDiseasesCount; i++) { Map.Entry<Disease, Integer> mapEntry = sortedDiseaseList.get(i); int previousDiseaseCount = (int) previousContacts.stream() .filter(c -> c.getDisease() == mapEntry.getKey()).count(); DashboardStatisticsDiseaseElement diseaseElement = new DashboardStatisticsDiseaseElement( mapEntry.getKey().toString(), mapEntry.getValue(), previousDiseaseCount); firstComponent.addComponentToContent(diseaseElement); } } else { contactClassificationUnconfirmedLarge.updatePercentageValueWithCount( contactClassificationUnconfirmedCount, contactClassificationUnconfirmedPercentage); contactClassificationConfirmedLarge.updatePercentageValueWithCount(contactClassificationConfirmedCount, contactClassificationConfirmedPercentage); contactClassificationNotAContactLarge.updatePercentageValueWithCount( contactClassificationNotAContactCount, contactClassificationNotAContactPercentage); newContactsLarge.updatePercentageValueWithCount(newContactsCount, newContactsPercentage); symptomaticContactsLarge.updatePercentageValueWithCount(symptomaticContactsCount, symptomaticContactsPercentage); } } @Override protected void addSecondComponent() { secondComponent = new DashboardStatisticsSubComponent(); // Header secondComponent.addHeader(I18nProperties.getString(Strings.headingContactFollowUp), null, true); // Content secondComponent.addMainContent(); underFollowUp = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardUnderFollowUp), CssStyles.SVG_FILL_PRIMARY); underFollowUp.setDescription(FollowUpStatus.FOLLOW_UP.getDescription()); followUpCompleted = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardCompletedFollowUp), CssStyles.SVG_FILL_POSITIVE); followUpCompleted.setDescription(FollowUpStatus.COMPLETED.getDescription()); followUpCanceled = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardCanceledFollowUp), CssStyles.SVG_FILL_IMPORTANT); followUpCanceled.setDescription(FollowUpStatus.CANCELED.getDescription()); lostToFollowUp = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardLostToFollowUp), CssStyles.SVG_FILL_CRITICAL); lostToFollowUp.setDescription(FollowUpStatus.LOST.getDescription()); contactStatusConverted = new DashboardStatisticsPercentageElement( I18nProperties.getCaption(Captions.dashboardConvertedToCase), CssStyles.SVG_FILL_NEUTRAL); contactStatusConverted .setDescription(I18nProperties.getDescription(Descriptions.descDashboardConvertedToCase)); secondComponent.addComponentToContent(underFollowUp); secondComponent.addComponentToContent(followUpCompleted); secondComponent.addComponentToContent(followUpCanceled); secondComponent.addComponentToContent(lostToFollowUp); secondComponent.addComponentToContent(contactStatusConverted); subComponentsLayout.addComponent(secondComponent, SECOND_LOC); } @Override protected void updateSecondComponent(int visibleDiseasesCount) { List<DashboardContactDto> contacts = dashboardDataProvider.getContacts(); contacts.removeIf(c -> c.getFollowUpStatus() == FollowUpStatus.NO_FOLLOW_UP); int contactsCount = contacts.size(); secondComponent.updateCountLabel(contactsCount); int underFollowUpCount = (int) contacts.stream() .filter(c -> c.getFollowUpStatus() == FollowUpStatus.FOLLOW_UP).count(); int underFollowUpPercentage = contactsCount == 0 ? 0 : (int) ((underFollowUpCount * 100.0f) / contactsCount); int followUpCompletedCount = (int) contacts.stream() .filter(c -> c.getFollowUpStatus() == FollowUpStatus.COMPLETED).count(); int followUpCompletedPercentage = contactsCount == 0 ? 0 : (int) ((followUpCompletedCount * 100.0f) / contactsCount); int followUpCanceledCount = (int) contacts.stream() .filter(c -> c.getFollowUpStatus() == FollowUpStatus.CANCELED).count(); int followUpCanceledPercentage = contactsCount == 0 ? 0 : (int) ((followUpCanceledCount * 100.0f) / contactsCount); int lostToFollowUpCount = (int) contacts.stream().filter(c -> c.getFollowUpStatus() == FollowUpStatus.LOST) .count(); int lostToFollowUpPercentage = contactsCount == 0 ? 0 : (int) ((lostToFollowUpCount * 100.0f) / contactsCount); int contactStatusConvertedCount = (int) contacts.stream() .filter(c -> c.getContactStatus() == ContactStatus.CONVERTED).count(); int contactStatusConvertedPercentage = contactsCount == 0 ? 0 : (int) ((contactStatusConvertedCount * 100.0f) / contactsCount); underFollowUp.updatePercentageValueWithCount(underFollowUpCount, underFollowUpPercentage); followUpCompleted.updatePercentageValueWithCount(followUpCompletedCount, followUpCompletedPercentage); followUpCanceled.updatePercentageValueWithCount(followUpCanceledCount, followUpCanceledPercentage); lostToFollowUp.updatePercentageValueWithCount(lostToFollowUpCount, lostToFollowUpPercentage); contactStatusConverted.updatePercentageValueWithCount(contactStatusConvertedCount, contactStatusConvertedPercentage); } @Override protected void addThirdComponent() { thirdComponent = new DashboardStatisticsSubComponent(); // Header thirdComponent.addHeader(I18nProperties.getString(Strings.headingFollowUpSituation), null, false); // Visit status of last visit thirdComponent.addMainContent(); CssLayout visitStatusCountLayout = thirdComponent.createCountLayout(true); cooperativeContacts = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardCooperative), CountElementStyle.POSITIVE); thirdComponent.addComponentToCountLayout(visitStatusCountLayout, cooperativeContacts); uncooperativeContacts = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardUncooperative), CountElementStyle.CRITICAL); thirdComponent.addComponentToCountLayout(visitStatusCountLayout, uncooperativeContacts); unavailableContacts = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardUnavailable), CountElementStyle.RELEVANT); thirdComponent.addComponentToCountLayout(visitStatusCountLayout, unavailableContacts); neverVisitedContacts = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardNeverVisited), CountElementStyle.MINOR); thirdComponent.addComponentToCountLayout(visitStatusCountLayout, neverVisitedContacts); Label infoLabel = new Label(VaadinIcons.INFO_CIRCLE.getHtml(), ContentMode.HTML); infoLabel.setSizeUndefined(); infoLabel.setDescription(I18nProperties.getDescription(Descriptions.descDashboardFollowUpInfo)); CssStyles.style(infoLabel, CssStyles.LABEL_LARGE, CssStyles.LABEL_SECONDARY, "follow-up-status-info-button"); thirdComponent.addComponentToCountLayout(visitStatusCountLayout, infoLabel); thirdComponent.addComponentToContent(visitStatusCountLayout); // Number of missed visits Label missedVisitsLabel = new Label(I18nProperties.getCaption(Captions.dashboardNotVisitedFor)); CssStyles.style(missedVisitsLabel, CssStyles.LABEL_BOLD, CssStyles.LABEL_PRIMARY, CssStyles.LABEL_UPPERCASE, CssStyles.LABEL_BACKGROUND_FOCUS_LIGHT, CssStyles.LABEL_ROUNDED_CORNERS_SLIM); thirdComponent.addComponentToContent(missedVisitsLabel); CssLayout missedVisitsCountLayout = thirdComponent.createCountLayout(false); missedVisitsOneDay = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardOneDay), CountElementStyle.PRIMARY); thirdComponent.addComponentToCountLayout(missedVisitsCountLayout, missedVisitsOneDay); missedVisitsTwoDays = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardTwoDays), CountElementStyle.PRIMARY); thirdComponent.addComponentToCountLayout(missedVisitsCountLayout, missedVisitsTwoDays); missedVisitsThreeDays = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardThreeDays), CountElementStyle.PRIMARY); thirdComponent.addComponentToCountLayout(missedVisitsCountLayout, missedVisitsThreeDays); missedVisitsGtThreeDays = new DashboardStatisticsCountElement( I18nProperties.getCaption(Captions.dashboardGtThreeDays), CountElementStyle.PRIMARY); thirdComponent.addComponentToCountLayout(missedVisitsCountLayout, missedVisitsGtThreeDays); thirdComponent.addComponentToContent(missedVisitsCountLayout); subComponentsLayout.addComponent(thirdComponent, THIRD_LOC); } @Override protected void updateThirdComponent(int visibleDiseasesCount) { List<DashboardContactDto> contacts = dashboardDataProvider.getContacts(); contacts.removeIf(c -> c.getFollowUpStatus() == FollowUpStatus.NO_FOLLOW_UP); int contactsCount = contacts.size(); int cooperativeContactsCount = (int) contacts.stream() .filter(c -> c.getLastVisitStatus() == VisitStatus.COOPERATIVE).count(); int cooperativeContactsPercentage = contactsCount == 0 ? 0 : (int) ((cooperativeContactsCount * 100.0f) / contactsCount); cooperativeContacts .updateCountLabel(cooperativeContactsCount + " (" + cooperativeContactsPercentage + " %)"); int uncooperativeContactsCount = (int) contacts.stream() .filter(c -> c.getLastVisitStatus() == VisitStatus.UNCOOPERATIVE).count(); int uncooperativeContactsPercentage = contactsCount == 0 ? 0 : (int) ((uncooperativeContactsCount * 100.0f) / contactsCount); uncooperativeContacts .updateCountLabel(uncooperativeContactsCount + " (" + uncooperativeContactsPercentage + " %)"); int unavailableContactsCount = (int) contacts.stream() .filter(c -> c.getLastVisitStatus() == VisitStatus.UNAVAILABLE).count(); int unavailableContactsPercentage = contactsCount == 0 ? 0 : (int) ((unavailableContactsCount * 100.0f) / contactsCount); unavailableContacts .updateCountLabel(unavailableContactsCount + " (" + unavailableContactsPercentage + " %)"); int notVisitedContactsCount = (int) contacts.stream().filter(c -> c.getLastVisitStatus() == null).count(); int notVisitedContactsPercentage = contactsCount == 0 ? 0 : (int) ((notVisitedContactsCount * 100.0f) / contactsCount); neverVisitedContacts .updateCountLabel(notVisitedContactsCount + " (" + notVisitedContactsPercentage + " %)"); int missedVisitsOneDayCount = 0; int missedVisitsTwoDaysCount = 0; int missedVisitsThreeDaysCount = 0; int missedVisitsGtThreeDaysCount = 0; for (DashboardContactDto contact : contacts) { Date lastVisitDateTime = contact.getLastVisitDateTime() != null ? contact.getLastVisitDateTime() : contact.getReportDate(); Date referenceDate; Date now = new Date(); // Current time should either be the end of the specified period or now if now is in the specified time interval if (DateHelper.isBetween(now, dashboardDataProvider.getFromDate(), dashboardDataProvider.getToDate())) { referenceDate = now; } else { referenceDate = dashboardDataProvider.getToDate(); } int missedDays = DateHelper.getFullDaysBetween(lastVisitDateTime, referenceDate); if (missedDays == 1) { missedVisitsOneDayCount++; } else if (missedDays == 2) { missedVisitsTwoDaysCount++; } else if (missedDays == 3) { missedVisitsThreeDaysCount++; } else if (missedDays > 3) { missedVisitsGtThreeDaysCount++; } } missedVisitsOneDay.updateCountLabel(missedVisitsOneDayCount); missedVisitsTwoDays.updateCountLabel(missedVisitsTwoDaysCount); missedVisitsThreeDays.updateCountLabel(missedVisitsThreeDaysCount); missedVisitsGtThreeDays.updateCountLabel(missedVisitsGtThreeDaysCount); } @Override protected void addFourthComponent() { fourthComponent = new DashboardStatisticsSubComponent(); // Header fourthComponent.addHeader(I18nProperties.getString(Strings.headingVisits), null, true); // Content fourthComponent.addMainContent(); unavailableVisits = new DashboardStatisticsGraphicalGrowthElement( I18nProperties.getCaption(Captions.dashboardUnavailable), CssStyles.SVG_FILL_MINOR); fourthComponent.addComponentToContent(unavailableVisits); uncooperativeVisits = new DashboardStatisticsGraphicalGrowthElement( I18nProperties.getCaption(Captions.dashboardUncooperative), CssStyles.SVG_FILL_IMPORTANT); fourthComponent.addComponentToContent(uncooperativeVisits); cooperativeVisits = new DashboardStatisticsGraphicalGrowthElement( I18nProperties.getCaption(Captions.dashboardCooperative), CssStyles.SVG_FILL_POSITIVE); fourthComponent.addComponentToContent(cooperativeVisits); Label separator = new Label("<hr/>", ContentMode.HTML); CssStyles.style(separator, CssStyles.VSPACE_TOP_3, CssStyles.VSPACE_3); fourthComponent.addComponentToContent(separator); missedVisits = new DashboardStatisticsGraphicalGrowthElement( I18nProperties.getCaption(Captions.dashboardMissed), CssStyles.SVG_FILL_CRITICAL); fourthComponent.addComponentToContent(missedVisits); subComponentsLayout.addComponent(fourthComponent, FOURTH_LOC); } @Override protected void updateFourthComponent(int visibleDiseasesCount) { List<DashboardContactDto> contacts = dashboardDataProvider.getContacts(); List<DashboardContactDto> previousContacts = dashboardDataProvider.getPreviousContacts(); List<DashboardVisitDto> visits = new ArrayList<>(); List<DashboardVisitDto> previousVisits = new ArrayList<>(); int doneEssentialVisitsCount = 0; // only visits that needed to be done, i.e. at most the amount of follow-up days int previousDoneEssentialVisitsCount = 0; VisitFacade visitFacade = FacadeProvider.getVisitFacade(); Date now = new Date(); int totalFollowUpDays = 0; int previousTotalFollowUpDays = 0; for (DashboardContactDto contact : contacts) { List<DashboardVisitDto> visitsForContact = visitFacade.getDashboardVisitsByContact( new ContactReferenceDto(contact.getUuid()), dashboardDataProvider.getFromDate(), dashboardDataProvider.getToDate()); visits.addAll(visitsForContact); if (contact.getFollowUpUntil() != null) { int contactFollowUpDays = Math.min(DateHelper.getDaysBetween(contact.getReportDate(), now), DateHelper.getDaysBetween(contact.getReportDate(), contact.getFollowUpUntil())); totalFollowUpDays += contactFollowUpDays; doneEssentialVisitsCount += visitsForContact.size() > contactFollowUpDays ? contactFollowUpDays : visitsForContact.size(); } } for (DashboardContactDto contact : previousContacts) { List<DashboardVisitDto> visitsForContact = visitFacade.getDashboardVisitsByContact( new ContactReferenceDto(contact.getUuid()), dashboardDataProvider.getPreviousFromDate(), dashboardDataProvider.getPreviousToDate()); previousVisits.addAll(visitsForContact); if (contact.getFollowUpUntil() != null) { int contactFollowUpDays = Math.min(DateHelper.getDaysBetween(contact.getReportDate(), now), DateHelper.getDaysBetween(contact.getReportDate(), contact.getFollowUpUntil())); previousTotalFollowUpDays += contactFollowUpDays; previousDoneEssentialVisitsCount += visitsForContact.size() > contactFollowUpDays ? contactFollowUpDays : visitsForContact.size(); } } int visitsCount = visits.size(); fourthComponent.updateCountLabel(visitsCount); int missedVisitsCount = totalFollowUpDays - doneEssentialVisitsCount; int unavailableVisitsCount = (int) visits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.UNAVAILABLE).count(); int uncooperativeVisitsCount = (int) visits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.UNCOOPERATIVE).count(); int cooperativeVisitsCount = (int) visits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.COOPERATIVE).count(); int previousMissedVisitsCount = previousTotalFollowUpDays - previousDoneEssentialVisitsCount; int previousUnavailableVisitsCount = (int) previousVisits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.UNAVAILABLE).count(); int previousUncooperativeVisitsCount = (int) previousVisits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.UNCOOPERATIVE).count(); int previousCooperativeVisitsCount = (int) previousVisits.stream() .filter(v -> v.getVisitStatus() == VisitStatus.COOPERATIVE).count(); int missedVisitsPercentage = totalFollowUpDays == 0 ? 0 : (int) ((missedVisitsCount * 100.0f) / totalFollowUpDays); int unavailableVisitsPercentage = visitsCount == 0 ? 0 : (int) ((unavailableVisitsCount * 100.0f) / visitsCount); int uncooperativeVisitsPercentage = visitsCount == 0 ? 0 : (int) ((uncooperativeVisitsCount * 100.0f) / visitsCount); int cooperativeVisitsPercentage = visitsCount == 0 ? 0 : (int) ((cooperativeVisitsCount * 100.0f) / visitsCount); int missedVisitsGrowth = calculateGrowth(missedVisitsCount, previousMissedVisitsCount); int unavailableVisitsGrowth = calculateGrowth(unavailableVisitsCount, previousUnavailableVisitsCount); int uncooperativeVisitsGrowth = calculateGrowth(uncooperativeVisitsCount, previousUncooperativeVisitsCount); int cooperativeVisitsGrowth = calculateGrowth(cooperativeVisitsCount, previousCooperativeVisitsCount); missedVisits.update(missedVisitsCount, missedVisitsPercentage, missedVisitsGrowth, false, false); unavailableVisits.update(unavailableVisitsCount, unavailableVisitsPercentage, unavailableVisitsGrowth, false, false); uncooperativeVisits.update(uncooperativeVisitsCount, uncooperativeVisitsPercentage, uncooperativeVisitsGrowth, false, false); cooperativeVisits.update(cooperativeVisitsCount, cooperativeVisitsPercentage, cooperativeVisitsGrowth, true, false); } @Override protected int getFullHeight() { return 430; } @Override protected int getNormalHeight() { return 320; } @Override protected int getFilteredHeight() { return 320; } }