class StatusVisitor implements ChangeSetVisitor, SkippedChangeSetVisitor {

    private final LinkedHashMap<ChangeSet, ChangeSetStatus> changeSetStatuses = new LinkedHashMap<>();
    private final List<RanChangeSet> ranChangeSets;

    public StatusVisitor(Database database) throws LiquibaseException {
        ranChangeSets = new ArrayList<>(
            Scope.getCurrentScope().getSingleton(ChangeLogHistoryServiceFactory.class).getChangeLogService(database).getRanChangeSets());
    }

    @Override
    public Direction getDirection() {
        return Direction.FORWARD;
    }

    @Override
    public void visit(ChangeSet changeSet, DatabaseChangeLog databaseChangeLog, Database database, Set<ChangeSetFilterResult> filterResults) throws LiquibaseException {
        ChangeSetStatus status = addStatus(changeSet);
        status.setWillRun(true);
        status.setFilterResults(filterResults);
    }

    @Override
    public void skipped(ChangeSet changeSet, DatabaseChangeLog databaseChangeLog, Database database, Set<ChangeSetFilterResult> filterResults) throws LiquibaseException {
        boolean needsChangeSetToBeSkipped = filterResults.stream().anyMatch(filter -> !filter.isAccepted());
        ChangeSetStatus status = new ChangeSetStatus(changeSet, needsChangeSetToBeSkipped);
        status.setWillRun(false);
        status.setFilterResults(filterResults);
        removeRanChangeSets(changeSet, status);
        changeSetStatuses.put(changeSet, status);
    }

    protected ChangeSetStatus addStatus(ChangeSet changeSet) {
        ChangeSetStatus status = new ChangeSetStatus(changeSet);
        removeRanChangeSets(changeSet, status);
        changeSetStatuses.put(changeSet, status);
        return status;
    }

    private void removeRanChangeSets(ChangeSet changeSet, ChangeSetStatus status) {
        RanChangeSet ranChangeSetToRemove = null;
        for (RanChangeSet ranChangeSet : ranChangeSets) {
            if (ranChangeSet.isSameAs(changeSet)) {
                status.setPreviouslyRan(true);
                status.setDateLastExecuted(ranChangeSet.getDateExecuted());
                status.setStoredCheckSum(ranChangeSet.getLastCheckSum());
                status.setRanChangeSet(ranChangeSet);

                ranChangeSetToRemove = ranChangeSet;

                break;
            }
        }
        if (ranChangeSetToRemove != null) {
            ranChangeSets.remove(ranChangeSetToRemove);
        }
    }

    /**
     * Convenience method to return the ChangeSetStatus of a given changeSet. Returns null if the changeSet is not know.
     */
    public ChangeSetStatus getStatus(ChangeSet changeSet) {
        return changeSetStatuses.get(changeSet);
    }

    /**
     * Return the status of all changeSets, in the order they exist in the databasechangelog.
     * Any changesets not in the current change log but previously ran against the database will be at the front of the List
     * with a not run reason type of {@link liquibase.changelog.filter.NotInChangeLogChangeSetFilter}
     */
    public List<ChangeSetStatus> getStatuses() {<FILL_FUNCTION_BODY>}

    /**
     * Return the changesets that will execute
     */
    public List<ChangeSetStatus> getChangeSetsToRun() {
        ArrayList<ChangeSetStatus> returnList = new ArrayList<>();
        for (ChangeSetStatus status : changeSetStatuses.values()) {
            if (status.getWillRun()) {
                returnList.add(status);
            }
        }

        return returnList;
    }

    /**
     * Return the changesets that will NOT execute
     */
    public List<ChangeSetStatus> getChangeSetsToSkip() {
        ArrayList<ChangeSetStatus> returnList = new ArrayList<>();
        for (ChangeSetStatus status : changeSetStatuses.values()) {
            if (!status.getWillRun()) {
                returnList.add(status);
            }
        }

        return returnList;
    }
}

        ArrayList<ChangeSetStatus> returnList = new ArrayList<>();
        for (RanChangeSet changeSet : ranChangeSets) {
            ChangeSetStatus status = new ChangeSetStatus(new ChangeSet(changeSet.getId(), changeSet.getAuthor(), false, false, changeSet.getChangeLog(), null, null, null));
            status.setPreviouslyRan(true);
            status.setDateLastExecuted(changeSet.getDateExecuted());
            status.setStoredCheckSum(changeSet.getLastCheckSum());

            status.setComments(changeSet.getComments());
            status.setDescription(changeSet.getDescription());
            status.setWillRun(false);
            status.setFilterResults(new HashSet<>(Collections.singletonList(new ChangeSetFilterResult(false, "Changeset is not in change log", NotInChangeLogChangeSetFilter.class))));
            status.setRanChangeSet(changeSet);

            returnList.add(status);
        }

        returnList.addAll(changeSetStatuses.values());

        return returnList;
    
<no_super_class>