package ru.yandex.webmaster3.core.sitestructure;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.jetbrains.annotations.Nullable;

/**
 * @author avhaliullin
 */
public class StructureNodeFilter {
    private final List<Part> filterParts;

    public StructureNodeFilter(List<Part> filterParts) {
        if (filterParts.isEmpty()) {
            this.filterParts = Collections.singletonList(new StringPart("/"));
        } else {
            this.filterParts = Collections.unmodifiableList(filterParts);
        }
    }

    public boolean isAcceptAllFilter() {
        return !filterParts.isEmpty() && filterParts.stream().allMatch(part -> part == WILDCARD);
    }

    public List<Part> getFilterParts() {
        return filterParts;
    }

    @Nullable
    public static StructureNodeFilter makeFilterForAutoNode(Collection<? extends TreeNode> nodes, long nodeId) {
        Map<Long, TreeNode> nodesMap = nodes.stream().collect(Collectors.toMap(TreeNode::getNodeId, Function.identity()));
        TreeNode node = nodesMap.get(nodeId);
        if (node == null) {
            return null;
        }
        List<TreeNode> reversedPath = new ArrayList<>();
        while (!node.isRootNode()) {
            reversedPath.add(node);
            node = nodesMap.get(node.getParentId());
        }
        StringBuilder pathBuilder = new StringBuilder();
        for (int i = reversedPath.size() - 1; i >= 0; i--) {
            pathBuilder.append(reversedPath.get(i).getRelativeName());
        }
        return new StructureNodeFilter(Arrays.asList(new StringPart(pathBuilder.toString()), WILDCARD));
    }

    public static StructureNodeFilter makeFilterForUserNode(SiteTreeNode node) {
        String nodeName = node.getName();
        if (nodeName.contains("*")) {
            List<Part> filterParts = new ArrayList<>();
            String[] parts = nodeName.split("\\*");
            for (String part : parts) {
                if (!part.isEmpty()) {
                    filterParts.add(new StringPart(part));
                    filterParts.add(WILDCARD);
                }
            }
            return new StructureNodeFilter(filterParts);
        } else {
            return new StructureNodeFilter(Arrays.asList(new StringPart(nodeName), WILDCARD));
        }
    }

    public static abstract class Part {}

    public static class StringPart extends Part {
        private final String value;

        public StringPart(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public static class WildcardPart extends Part {
        private WildcardPart() {}
    }


    public static WildcardPart WILDCARD = new WildcardPart();
}
