import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;

public class CarAnimation extends JFrame {

    public CarAnimation() {
        setTitle("Анимация с машинкой");
        setSize(1280, 720);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // панель анимации
        AnimationPanel panel = new AnimationPanel();
        JMenuBar menuBar = new JMenuBar();

        // меню файл
        JMenu fileMenu = new JMenu("Файл");
        JMenuItem useFolderItem = new JMenuItem("Использовать картинки из папки");
        JMenuItem exitItem = new JMenuItem("Выход");

        useFolderItem.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            // только папки
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            chooser.setDialogTitle("Выберите папку с изображениями машинок");

            int returnVal = chooser.showOpenDialog(CarAnimation.this);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                // выбранная папка в панель
                panel.loadImagesFromFolder(chooser.getSelectedFile());
            }
        });
        exitItem.addActionListener(e -> System.exit(0));

        fileMenu.add(useFolderItem);
        fileMenu.add(exitItem);

        // меню скорость
        JMenu speedMenu = new JMenu("Скорость машинки");
        JMenuItem slowSpeed = new JMenuItem("Медленно");
        JMenuItem normalSpeed = new JMenuItem("Нормально");
        JMenuItem fastSpeed = new JMenuItem("Быстро");

        slowSpeed.addActionListener(e -> panel.setSpeed(100));
        normalSpeed.addActionListener(e -> panel.setSpeed(50));
        fastSpeed.addActionListener(e -> panel.setSpeed(20));

        speedMenu.add(slowSpeed);
        speedMenu.add(normalSpeed);
        speedMenu.add(fastSpeed);

        // меню справка
        JMenu helpMenu = new JMenu("Справка");
        JMenuItem aboutItem = new JMenuItem("О программе");
        aboutItem.addActionListener(e -> JOptionPane.showMessageDialog(this, "Анимация машинки\nУправление: наведите мышь на окно."));
        helpMenu.add(aboutItem);

        // сборка менюбара
        menuBar.add(fileMenu);
        menuBar.add(speedMenu);
        menuBar.add(helpMenu);
        setJMenuBar(menuBar);
        
        add(panel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            CarAnimation app = new CarAnimation();
            app.setVisible(true);
        });
    }
}

class AnimationPanel extends JPanel implements MouseListener, java.awt.event.MouseMotionListener {
    private final BufferedImage[] frames;
    private int currentFrameIndex = 0;
    private volatile boolean isMouseInside = false; // флаг для управления потоком
    private final Thread animationThread;
    private volatile int speedDelay = 100; // переменная для скорости
    private BufferedImage[] currentFrames; // чтобы можно было менять массив картинок
    private volatile boolean isFolderMode = false; // true, если загружены файлы из папки

    // метод для изменения скорости
    public void setSpeed(int newSpeed) {
        this.speedDelay = newSpeed;
    }

    // метод для загрузки картинок из папки
    public void loadImagesFromFolder(File folder) {
        // список всех файлов в папке
        File[] files = folder.listFiles();

        if (files == null || files.length == 0) {
            JOptionPane.showMessageDialog(this, "Папка пуста!");
            return;
        }

        // только картинки (png, jpg, gif)
        File[] imageFiles = Arrays.stream(files)
                .filter(f -> f.getName().toLowerCase().endsWith(".png") || 
                            f.getName().toLowerCase().endsWith(".jpg") || 
                            f.getName().toLowerCase().endsWith(".jpeg") || 
                            f.getName().toLowerCase().endsWith(".gif"))
                .sorted(Comparator.comparing(File::getName)) // сортировка по имени
                .toArray(File[]::new);

        if (imageFiles.length == 0) {
            JOptionPane.showMessageDialog(this, "В выбранной папке нет подходящих изображений!");
            return;
        }

        // найденные файлы в массив BufferedImage
        BufferedImage[] newFrames = new BufferedImage[imageFiles.length];
        try {
            for (int i = 0; i < imageFiles.length; i++) {
                newFrames[i] = ImageIO.read(imageFiles[i]);
            }
            
            // обновляем массив в панели
            this.currentFrames = newFrames;
            this.isFolderMode = true;
            this.currentFrameIndex = 0; // Сбрасываем кадр на первый
            this.repaint();
            
            JOptionPane.showMessageDialog(this, "Загружено кадров: " + newFrames.length);
            
        } catch (IOException e) {
            JOptionPane.showMessageDialog(this, "Ошибка при чтении файлов: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private int carX = 0; 
    public AnimationPanel() {
        // подготовка изображений
        frames = prepareImages();
        this.currentFrames = prepareImages();

        // создание и запуск потока анимации
        animationThread = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                try {
                    if (carX > getWidth()) {
                        carX = -200; // Сбрасываем на ширину новой машинки, чтобы она выезжала плавно
                    }
                    if (isMouseInside) {
                        // Двигаем машинку вправо
                        carX += 15; 
                        // Если машинка уехала за правый край, возвращаем её за левый край
                        if (carX > getWidth()) {
                            carX = -100; 
                        }
                        
                        // Если нужны еще и смены кадров (анимация колес и т.д.)
                        currentFrameIndex = (currentFrameIndex + 1) % frames.length;
                        
                        repaint();
                        Thread.sleep(speedDelay);
                    } else {
                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
        });
        animationThread.start();
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    private BufferedImage createDummyCar(int frame, int total) {
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();

        // 1. Рисуем корпус машинки
        g.setColor(Color.RED);
        g.fillRect(0, 40, 100, 40); 
        
        // крыша
        g.setColor(Color.RED);
        g.fillRect(20, 20, 60, 20);

        // 2. Рисуем окна
        // Цвет стекла (светло-голубой)
        g.setColor(new Color(173, 216, 230)); 
        
        // Переднее окно
        g.fillRect(30, 25, 15, 15); 
        // Заднее окно
        g.fillRect(55, 25, 15, 15); 

        // // Добавляем черную обводку для окон, чтобы они были четкими
        // g.setColor(Color.BLACK);
        // g.drawRect(20, 45, 25, 15);
        // g.drawRect(50, 45, 25, 15);

        // 3. Рисуем колеса
        g.setColor(Color.BLACK);
        g.fillOval(10, 70, 20, 20);
        g.fillOval(70, 70, 20, 20);

        g.dispose();
        return img;
    }

    private BufferedImage[] prepareImages() {
        int frameCount = 1; // количество кадров
        this.isFolderMode = false; 
        BufferedImage[] imgArray = new BufferedImage[frameCount];

        // создание болванок
        for (int i = 0; i < frameCount; i++) {
            imgArray[i] = createDummyCar(i, frameCount);
        }

        return imgArray;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (frames.length > 0) {
            // 1. Параметры машинки
            int originalWidth = frames[0].getWidth();
            int originalHeight = frames[0].getHeight();
            int newWidth = originalWidth * 2;
            int newHeight = originalHeight * 2;
            int x = carX; 
            int y = (getHeight() - newHeight) / 2;

            // 2. Параметры дороги
            int roadHeight = 80;
            int roadY = y + newHeight - 90; // Дорога под колесами

            // --- ОТРИСОВКА ФОНА (СЛОИ) ---

            // Слой 1: Небо (голубое)
            // Рисуем на весь экран
            g.setColor(new Color(135, 206, 235)); // Цвет SkyBlue
            g.fillRect(0, 0, getWidth(), getHeight());

            // Слой 2: Трава (темно-зеленая)
            // Рисуем от нижней границы дороги до самого низа экрана
            g.setColor(new Color(34, 139, 34)); // Цвет ForestGreen
            int grassStartY = roadY + roadHeight;
            int grassHeight = getHeight() - grassStartY;
            if (grassHeight > 0) {
                g.fillRect(0, grassStartY, getWidth(), grassHeight);
            }

            // Слой 3: Дорога (темно-серая)
            g.setColor(Color.DARK_GRAY);
            g.fillRect(0, roadY, getWidth(), roadHeight);

            // Слой 4: Разметка (белая)
            g.setColor(Color.WHITE);
            for (int i = 0; i < getWidth(); i += 60) {
                g.fillRect(i, roadY + (roadHeight / 2) - 3, 30, 6);
            }

            // --- ОТРИСОВКА ОБЪЕКТОВ ---

            // Слой 5: Машинка (поверх всего)
            g.drawImage(currentFrames[currentFrameIndex], x, y, newWidth, newHeight, this);
        }

        if (isFolderMode) {
        g.setColor(Color.BLUE);
        g.drawString("Кадров в папке: " + currentFrames.length, 10, 40);
        }

        // подсказка
        g.setColor(Color.GRAY);
        g.drawString(isMouseInside ? "Статус: Анимация работает" : "Статус: Пауза (мышь снаружи)", 10, 20);
    }

    // Реализация методов MouseListener
    @Override
    public void mouseEntered(MouseEvent e) {
        isMouseInside = true; // запуск
    }

    @Override
    public void mouseExited(MouseEvent e) {
        isMouseInside = false; // остановка
    }

    @Override public void mouseClicked(MouseEvent e) {}
    @Override public void mousePressed(MouseEvent e) {}
    @Override public void mouseReleased(MouseEvent e) {}
    @Override public void mouseMoved(MouseEvent e) {}
    @Override public void mouseDragged(MouseEvent e) {}
}