package ffm; /// usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 11

import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Execute with JBang to force Java 11: jbang Java11PixelBuffer.java
 */
public class Java11PixelBuffer {

    private static final int WIDTH = 500;
    private static final int HEIGHT = 500;
    private static float timeOffset = 0.0f;
    private static ScheduledExecutorService executor;
    private static long timestamp = System.currentTimeMillis();
    private static BufferedImage bufferedImage;
    private static ImageIcon imageIcon;
    private static JLabel imageLabel;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            createAndShowGUI();
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                if (executor != null) {
                    executor.shutdown();
                }
            }));
        });
    }

    private static void createAndShowGUI() {
        executor = Executors.newSingleThreadScheduledExecutor();

        // Create initial image with gradient pattern
        bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        imageIcon = new ImageIcon(bufferedImage);
        imageLabel = new JLabel(imageIcon);
        createGradient();

        // Start scheduled task to update the image every 5ms
        executor.scheduleAtFixedRate(() -> {
            try {
                timeOffset += 0.1f;
                updateImage();
            } catch (Exception e) {
                System.err.println("Error in scheduled task: " + e.getMessage());
            }
        }, 2000, 5, TimeUnit.MILLISECONDS);

        // Display in a JFrame
        JFrame frame = new JFrame("Java 11 - Animated Gradient Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(imageLabel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        // Shutdown executor on window close
        frame.addWindowListener(new java.awt.event.WindowAdapter() {
            @Override
            public void windowClosing(java.awt.event.WindowEvent e) {
                if (executor != null) {
                    executor.shutdown();
                }
                System.out.println("Shutdown executor");
            }
        });
    }

    private static void updateImage() {
        createGradient();
        SwingUtilities.invokeLater(() -> {
            imageIcon.setImage(bufferedImage);
            imageLabel.repaint();
        });
    }

    /**
     * Create a gradient in the BufferedImage with animated gradient pattern.
     */
    private static void createGradient() {
        // Get the image's raster data for direct pixel access
        int[] pixelData = new int[WIDTH * HEIGHT];

        for (int y = 0; y < HEIGHT; y++) {
            for (int x = 0; x < WIDTH; x++) {
                int pixelIndex = y * WIDTH + x;

                // Create animated gradient effect using trigonometric functions
                int red = (int) (((Math.sin(x * 0.1f + timeOffset) + 1) * 127.5f));
                int green = (int) (((Math.cos(y * 0.1f + timeOffset) + 1) * 127.5f));
                int blue = (int) (((Math.sin((x + y) * 0.1f + timeOffset) + 1) * 127.5f));
                int alpha = 255; // Fully opaque

                // Clamp values to valid byte range
                red = Math.max(0, Math.min(255, red));
                green = Math.max(0, Math.min(255, green));
                blue = Math.max(0, Math.min(255, blue));

                // Pack ARGB into single integer
                int argb = (alpha << 24) | (red << 16) | (green << 8) | blue;
                pixelData[pixelIndex] = argb;
            }
        }

        // Set all pixels at once for better performance
        bufferedImage.setRGB(0, 0, WIDTH, HEIGHT, pixelData, 0, WIDTH);

        var now = System.currentTimeMillis();
        System.out.println("Interval: " + (now - timestamp) + " - Generated " + (WIDTH * HEIGHT) + " pixels");
        timestamp = now;
    }
}
