

package com.github.lukaszkusek.xml.comparator.comparators.children.cost;

import java.util.Collection;

import com.github.lukaszkusek.xml.comparator.XMLComparator;
import com.github.lukaszkusek.xml.comparator.diff.DifferenceCode;
import com.github.lukaszkusek.xml.comparator.diff.DifferenceDetails;
import com.github.lukaszkusek.xml.comparator.node.INode;
import com.github.lukaszkusek.xml.comparator.node.Node;
import com.google.common.collect.Lists;

public class CostCalculator {

    private XMLComparator xmlComparator;

    public CostCalculator(XMLComparator xmlComparator) {
        this.xmlComparator = xmlComparator;
    }

    public CostMatrix compareChildren(Collection<Node> children1, Collection<Node> children2) {
        int size1 = children1.size();
        int size2 = children2.size();

        int max = Math.max(size1, size2);

        Collection<INode> nullableChildren1 = fillUpWithNullNodes(children1, max - size1);
        Collection<INode> nullableChildren2 = fillUpWithNullNodes(children2, max - size2);

        return createChildrenComparisonMatrix(nullableChildren1, nullableChildren2);
    }

    private Collection<INode> fillUpWithNullNodes(Collection<Node> children, int childrenToAddCount) {
        Collection<INode> nullableChildren = Lists.newArrayList();
        nullableChildren.addAll(children);

        for (int i = 0; i < childrenToAddCount; i++) {
            nullableChildren.add(new NullNode());
        }

        return nullableChildren;
    }

    private CostMatrix createChildrenComparisonMatrix(
            Collection<INode> nullableChildren1, Collection<INode> nullableChildren2) {

        CostMatrix childrenComparisonMatrix = CostMatrix.create(nullableChildren1, nullableChildren2);

        nullableChildren1.forEach(child1 ->
                nullableChildren2.forEach(child2 ->
                        childrenComparisonMatrix.put(child1, child2, compare(child1, child2))));

        return childrenComparisonMatrix;
    }

    private DifferenceDetails compare(INode node1, INode node2) {
        if (node1.isNull() && node2.isNull()) {
            throw new RuntimeException("node1 && node2 cannot be NullNode at the same time.");
        }

        if (node1.isNull()) {
            return DifferenceDetails.of(null, (Node) node2, DifferenceCode.MISSING_ELEMENT_IN_FIRST_DOCUMENT);
        }

        if (node2.isNull()) {
            return DifferenceDetails.of((Node) node1, null, DifferenceCode.MISSING_ELEMENT_IN_SECOND_DOCUMENT);
        }

        return xmlComparator.compare((Node) node1, (Node) node2);
    }
}
