/*
 * Autopsy Forensic Browser
 *
 * Copyright 2014-16 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> org
 *
 * 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.
 */
package org.sleuthkit.autopsy.timeline.ui.filtering;

import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.scene.control.TreeItem;
import org.sleuthkit.autopsy.timeline.filters.CompoundFilter;
import org.sleuthkit.autopsy.timeline.filters.Filter;

/**
 * A TreeItem for a filter.
 */
final public class FilterTreeItem extends TreeItem<Filter> {

    /**
     * recursively construct a tree of TreeItems to parallel the filter tree of
     * the given filter
     *
     *
     * @param filter the filter for this item. if f has sub-filters, tree items
     *               will be made for them added added to the children of this
     *               FilterTreeItem
     */
    public FilterTreeItem(Filter filter, ObservableMap<Filter, Boolean> expansionMap) {
        super(filter);

        //listen to changes in the expansion map, and update expansion state of filter object
        expansionMap.addListener((MapChangeListener.Change<? extends Filter, ? extends Boolean> change) -> {
            if (change.getKey().equals(filter)) {
                setExpanded(expansionMap.get(change.getKey()));
            }
        });

        if (expansionMap.containsKey(filter)) {
            setExpanded(expansionMap.get(filter));
        }

        //keep expanion map upto date if user expands/collapses filter
        expandedProperty().addListener(expandedProperty -> expansionMap.put(filter, isExpanded()));

        //if the filter is a compound filter, add its subfilters to the tree
        if (filter instanceof CompoundFilter<?>) {
            final CompoundFilter<?> compoundFilter = (CompoundFilter<?>) filter;

            //add all sub filters
            compoundFilter.getSubFilters().forEach(subFilter -> getChildren().add(new FilterTreeItem(subFilter, expansionMap)));

            //listen to changes in sub filters and keep tree in sync
            compoundFilter.getSubFilters().addListener((ListChangeListener.Change<? extends Filter> c) -> {
                while (c.next()) {
                    for (Filter subfFilter : c.getAddedSubList()) {
                        setExpanded(true); //emphasize new filters by expanding parent to make sure they are visible
                        getChildren().add(new FilterTreeItem(subfFilter, expansionMap));
                    }
                }
            });

            /*
             * enforce the following relationship between a compound filter and
             * its subfilters: if a compound filter's active property changes,
             * disable the subfilters if the compound filter is not active.
             */
            compoundFilter.activeProperty().addListener(activeProperty -> {
                compoundFilter.getSubFilters().forEach(subFilter -> subFilter.setDisabled(compoundFilter.isActive() == false));
            });
        }
    }
}

@@ -3463,82 +3463,414 @@
     
-compoundFilter.getSubFilters().forEach(subFilter -%3E subFilter.setDisabled(
+disableSubFiltersIfNotActive(compoundFilter);%0A            %7D);%0A%0A            disableSubFiltersIfNotActive(compoundFilter);%0A        %7D%0A    %7D%0A%0A    /**%0A     * disable the sub-filters of the given compound filter if it is not active%0A     *%0A     * @param compoundFilter the compound filter%0A     */%0A    static private void disableSubFiltersIfNotActive(CompoundFilter%3C?%3E compoundFilter) %7B%0A        boolean inactive = 
 comp
@@ -3899,18 +3899,16 @@
 == false
-))
 ;%0A      
@@ -3913,25 +3913,93 @@
     
-    %7D);%0A        %7D
+compoundFilter.getSubFilters().forEach(subFilter -%3E subFilter.setDisabled(inactive));
 %0A   

set initial disabled state of sub filters based on active state of compound filter