package com.knecon.fforesight.service.layoutparser.processor.services.graphics;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

@Service
public class GraphicsClusteringService {

    public List<Box> getClusters(List<Box> boxes, double tol) {

        if (boxes.isEmpty()) {
            return boxes;
        } else {
            // We iteratively pick a Box that intersects at least one other box and replace the
            // intersecting box with a Box containing them
            var currentBoxes = boxes;
            var foundIntersectingBoxes = true;
            while (foundIntersectingBoxes) {
                foundIntersectingBoxes = false;

                // The box we are going to check to see if there are any intersecting boxes, followed by
                // any boxes that we have already check
                var checked = List.of(currentBoxes.get(0));
                var unchecked = currentBoxes.subList(1, currentBoxes.size());

                while (!foundIntersectingBoxes && !unchecked.isEmpty()) {

                    List<Box> intersects = new ArrayList<>();
                    List<Box> nonIntersects = new ArrayList<>();

                    for (Box uncheck : unchecked) {
                        if (uncheck.intersects(checked.get(0), tol)) {
                            intersects.add(uncheck);
                        } else {
                            nonIntersects.add(uncheck);
                        }
                    }

                    if (!intersects.isEmpty()) {
                        List<Box> combinedIntersecting = new ArrayList<>();
                        combinedIntersecting.add(checked.get(0));
                        combinedIntersecting.addAll(intersects);
                        var newBox = merge(combinedIntersecting);

                        List<Box> newCurrentBoxes = new ArrayList<>();
                        newCurrentBoxes.add(newBox);
                        newCurrentBoxes.addAll(checked.subList(1, checked.size()));
                        newCurrentBoxes.addAll(nonIntersects);
                        currentBoxes = newCurrentBoxes;
                        foundIntersectingBoxes = true; // Exit this loop and re-enter the outer loop
                    } else {
                        List<Box> newChecked = new ArrayList<>();
                        newChecked.add(unchecked.get(0));
                        newChecked.addAll(checked);
                        checked = newChecked;
                        unchecked = unchecked.subList(1, unchecked.size());
                    }
                }
            }
            return currentBoxes;
        }
    }


    public Box merge(List<Box> boxes) {

        double minX = Double.POSITIVE_INFINITY;
        double minY = Double.POSITIVE_INFINITY;
        double maxX = Double.NEGATIVE_INFINITY;
        double maxY = Double.NEGATIVE_INFINITY;

        for (Box box : boxes) {
            minX = Math.min(minX, box.x1);
            minY = Math.min(minY, box.y1);
            maxX = Math.max(maxX, box.x2);
            maxY = Math.max(maxY, box.y2);
        }
        return new Box(minX, minY, maxX, maxY);
    }

}
