import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import javax.swing.*;

/**
 * Recreation of the Cards application in the supplied recording.
 *
 * VS Code: open the folder containing this file, open Experiment1.java,
 * and choose Run above main (requires a JDK and Java language support).
 * Terminal alternative, with JDK 11 or newer: java Experiment1.java
 * Or: javac Experiment1.java followed by java Experiment1
 * No libraries, images, build system, or other source files are required.
 *
 * Observed: initially empty gray window; File > New / New 5 / New 10 / Exit;
 * sorted overlapping cards; hover lifts a card; selecting removes it from
 * the hand and displays it above; the remaining hand stays centered.
 *
 * Assumptions: values are sampled without replacement from 1..20 (the range
 * visible in the video). New chooses a random count from 1..10; the exact
 * original count distribution cannot be determined. Each new deal clears
 * the upper card. Only the most recently played card is displayed above.
 * Hover and play changes are immediate: no timed travel is clearly visible.
 * Window decoration/font rendering depends on the operating system.
 * Audio, the background IDE, and desktop controls are outside this recreation.
 */

public class Solution2 extends JPanel {
    private static final long serialVersionUID = 1L;
    static final int CARD_WIDTH = 80, CARD_HEIGHT = 120, CARD_STEP = 58;
    static final int HOVER_LIFT = 14, MAX_NUMBER = 20;
    private final Random random = new Random();
    final ArrayList<Integer> hand = new ArrayList<>();
    Integer played;
    int hovered = -1;

    public Solution2() {
        setPreferredSize(new Dimension(1000, 550));
        setBackground(new Color(238, 238, 238));
        setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15));
        MouseAdapter mouse = new MouseAdapter() {
            @Override public void mouseMoved(MouseEvent e) {
                updateHover(e.getPoint());
            }
            @Override public void mouseExited(MouseEvent e) {
                hovered = -1;
                repaint();
            }
            @Override public void mousePressed(MouseEvent e) {
                if (SwingUtilities.isLeftMouseButton(e)) {
                    int index = cardAt(e.getPoint());
                    if (index >= 0) {
                        play(index);
                        updateHover(e.getPoint());
                    }
                }
            }
        };
        addMouseListener(mouse);
        addMouseMotionListener(mouse);
        addComponentListener(new ComponentAdapter() {
            @Override public void componentResized(ComponentEvent e) {
                hovered = -1;
                repaint();
            }
        });
    }

    void deal(int count) {
        if (count < 1 || count > MAX_NUMBER) {
            throw new IllegalArgumentException("Card count must be between 1 and 20.");
        }
        ArrayList<Integer> deck = new ArrayList<>();
        for (int n = 1; n <= MAX_NUMBER; n++) deck.add(n);
        Collections.shuffle(deck, random);
        hand.clear();
        hand.addAll(deck.subList(0, count));
        Collections.sort(hand);
        played = null;
        hovered = -1;
        repaint();
    }

    void play(int index) {
        if (index < 0 || index >= hand.size()) return;
        played = hand.remove(index);
        hovered = -1;
        repaint();
    }

    private int step() {
        if (hand.size() < 2) return CARD_STEP;
        return Math.min(CARD_STEP,
                Math.max(1, (getWidth() - CARD_WIDTH - 40) / (hand.size() - 1)));
    }

    Rectangle cardBounds(int index) {
        int span = CARD_WIDTH + Math.max(0, hand.size() - 1) * step();
        int x = (getWidth() - span) / 2 + index * step();
        int y = getHeight() - CARD_HEIGHT - 80;
        if (index == hovered) y -= HOVER_LIFT;
        return new Rectangle(x, y, CARD_WIDTH, CARD_HEIGHT);
    }

    int cardAt(Point point) {
        // Reverse paint order: a card to the right covers its left neighbor.
        for (int i = hand.size() - 1; i >= 0; i--) {
            Rectangle r = cardBounds(i);
            if (new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, 12, 12)
                    .contains(point)) return i;
        }
        return -1;
    }

    private void updateHover(Point point) {
        int next = cardAt(point);
        if (next != hovered) {
            hovered = next;
            repaint();
        }
    }

    @Override protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D g = (Graphics2D) graphics.create();
        try {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            if (played != null) {
                drawCard(g, played, new Rectangle((getWidth() - CARD_WIDTH) / 2,
                        65, CARD_WIDTH, CARD_HEIGHT));
            }
            for (int i = 0; i < hand.size(); i++) {
                drawCard(g, hand.get(i), cardBounds(i));
            }
        } finally {
            g.dispose();
        }
    }

    private void drawCard(Graphics2D g, int number, Rectangle r) {
        g.setColor(new Color(214, 214, 214));
        g.fillRoundRect(r.x, r.y, r.width, r.height, 12, 12);
        g.setColor(new Color(120, 120, 120));
        g.drawRoundRect(r.x, r.y, r.width, r.height, 12, 12);
        g.setColor(new Color(35, 35, 35));
        g.setFont(getFont());
        g.drawString(Integer.toString(number), r.x + 9, r.y + 22);
    }

    private JMenuBar createMenu(JFrame frame) {
        JMenuBar bar = new JMenuBar();
        JMenu file = new JMenu("File");
        file.setMnemonic(KeyEvent.VK_F);
        String[] labels = {"New", "New 5", "New 10", "Exit"};
        for (int i = 0; i < labels.length; i++) {
            final int action = i;
            JMenuItem item = new JMenuItem(labels[i]);
            item.addActionListener(e -> {
                switch (action) {
                    case 0: deal(1 + random.nextInt(10)); break;
                    case 1: deal(5); break;
                    case 2: deal(10); break;
                    case 3: frame.dispose(); break;
                    default: break;
                }
            });
            file.add(item);
        }
        bar.add(file);
        return bar;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception ignored) {
                // Swing's default appearance remains usable on every platform.
            }
            JFrame frame = new JFrame("Cards");
            Solution2 cards = new Solution2();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setJMenuBar(cards.createMenu(frame));
            frame.setContentPane(cards);
            frame.setMinimumSize(new Dimension(480, 460));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}
