package com.knecon.fforesight.service.layoutparser.processor.utils;

import java.awt.geom.AffineTransform;

import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;

@UtilityClass
public class CoordinateTransforms {

    public AffineTransform calculateImageCoordsToInitialUserSpaceCoords(PageInformation pageInformation, double scalingFactor) {

        AffineTransform imageToCropBoxScaling = new AffineTransform(scalingFactor, 0, 0, scalingFactor, -pageInformation.minX(), -pageInformation.minY());

        AffineTransform mirrorMatrix = new AffineTransform(1, 0, 0, -1, 0, pageInformation.height());

        AffineTransform rotationMatrix = switch (pageInformation.rotationDegrees()) {
            case 90 -> new AffineTransform(0, 1, -1, 0, pageInformation.height(), 0);
            case 180 -> new AffineTransform(-1, 0, 0, -1, pageInformation.width(), pageInformation.height());
            case 270 -> new AffineTransform(0, -1, 1, 0, pageInformation.width() - pageInformation.height(), pageInformation.height()); // results from 90 + 180 rotations
            default -> new AffineTransform();
        };

        // matrix multiplication is performed from right to left, so the order is reversed.
        // scaling -> mirror -> rotation
        AffineTransform resultMatrix = new AffineTransform();

        resultMatrix.concatenate(rotationMatrix);
        resultMatrix.concatenate(mirrorMatrix);
        resultMatrix.concatenate(imageToCropBoxScaling);
        return resultMatrix;
    }


    @SneakyThrows
    public AffineTransform calculateInitialUserSpaceCoordsToImageCoords(PageInformation pageInformation, double scalingFactor) {

        return calculateImageCoordsToInitialUserSpaceCoords(pageInformation, scalingFactor).createInverse();
    }


    public AffineTransform calculatePageCoordsToInitialUserSpaceCoords(PageInformation pageInformation) {

        return calculateImageCoordsToInitialUserSpaceCoords(pageInformation, 1);
    }


    @SneakyThrows
    public AffineTransform calculateInitialUserSpaceCoordsToPageCoords(PageInformation pageInformation) {

        return calculatePageCoordsToInitialUserSpaceCoords(pageInformation).createInverse();
    }


    public double calculateScalingFactor(PageInformation pageInformation, double imageWidth) {

        // PDFBox always returns page height and width based on rotation
        double pageWidth;
        if (pageInformation.rotationDegrees() == 90 || pageInformation.rotationDegrees() == 270) {
            pageWidth = pageInformation.height();
        } else {
            pageWidth = pageInformation.width();
        }

        return pageWidth / imageWidth;
    }

}
