import java.awt.*;
import java.awt.image.BufferedImage;

public class JuliaDrawThread extends Thread {

    private final int threadNumber;
    private final int totalThreads;
    private final int imageSectionHeight;
    private final BufferedImage partialImage;
    private final JuliaSet obj;

    public void run() {
        generateImagePart();
    }

    public BufferedImage getPartialImage() {
        return this.partialImage;
    }

    private void generateImagePart() {
        float pixelBrightness;
        double complexX, complexY;
        ComplexNumber z;
        int i;

        int startCoordinate = (int) Math.floor(((float) this.obj.imageRectY / totalThreads)) * this.threadNumber;

        int endCoordinate = startCoordinate + imageSectionHeight;

        double aspectRatio = (double) this.obj.imageRectY / (double) this.obj.imageRectX;

        double mouseX = obj.mouseOffsetX / (double) obj.imageRectX / obj.zoom;
        double mouseY = obj.mouseOffsetY / (double) obj.imageRectY / obj.zoom;

        // Iterate over every pixel
        for (int x = 0; x < this.obj.imageRectX; x++) {
            for (int y = startCoordinate; y < endCoordinate; y++) {
                pixelBrightness = 0.0 f;

                complexX = (((((double) obj.imageRectX / 2) - x) / (((double) obj.imageRectX / 2) / 2)) / obj.zoom) + (mouseX * obj.zoom);
                complexY = aspectRatio * ((((y - ((double) obj.imageRectY / 2)) / (((double) obj.imageRectY / 2) / 2))) / obj.zoom) - (mouseY * obj.zoom);

                z = new ComplexNumber(complexX, complexY);

                // Loop until we've reached the maximum number of iterations
                for (i = 0; i < obj.juliaIterations; i++) {
                    z.square();
                    z.add(new ComplexNumber(obj.juliaCX, obj.juliaCY));

                    // Break out of the loop
                    if (z.modulus() > 2) {
                        // Set brightness to max
                        pixelBrightness = 1.0 f;
                        break;
                    }
                }

                // Brings the color value from e.g 0-300 to somewhere between 0-1
                float colorValue = (i % this.obj.juliaIterations) / ((float) this.obj.juliaIterations - 1);

                // Variant 1
                if (this.obj.selectedColorMethod == 1) {
                    partialImage.setRGB(x, y - startCoordinate, Color.getHSBColor(colorValue, 1, pixelBrightness).getRGB());
                }

                // Variant 2: One colour
                else if (this.obj.selectedColorMethod == 2) {
                    if (colorValue < obj.blackThresholdSliderFactor) {
                        partialImage.setRGB(x, y - startCoordinate, Color.getHSBColor((float) obj.colorHueSliderFactor / 100, 1, 0).getRGB());
                    } else {
                        partialImage.setRGB(x, y - startCoordinate, Color.getHSBColor((float) obj.colorHueSliderFactor / 100, 1, Math.min(colorValue * (float)(obj.colorBrightnessSliderFactor), 1.0 f)).getRGB());
                    }
                }
            }
        }
    }

    JuliaDrawThread(int threadNr, int totalThreads, JuliaSet obj) {
        this.threadNumber = threadNr;
        this.totalThreads = totalThreads;
        this.obj = obj;

        if (this.threadNumber != this.totalThreads - 1) {
            this.imageSectionHeight = (int) Math.floor((float) this.obj.imageRectY / this.totalThreads);
        } else {
            this.imageSectionHeight = (int) Math.floor((float) this.obj.imageRectY / this.totalThreads) + (this.obj.imageRectY % this.totalThreads) + 1;
        }

        partialImage = new BufferedImage(obj.imageRectX, this.imageSectionHeight, BufferedImage.TYPE_INT_RGB);
    }
}