001package jmri.jmrit.etcs.dmi.swing;
002
003import java.awt.Font;
004import java.awt.FontMetrics;
005import java.util.ArrayList;
006import java.util.List;
007
008import javax.swing.JFrame;
009import javax.swing.JLabel;
010
011import jmri.jmrit.etcs.CabMessage;
012
013import org.apiguardian.api.API;
014
015/**
016 * Class to represent a CabMessage received by the DMI.
017 * @author Steve Young Copyright (C) 2024
018 */
019@API(status=API.Status.EXPERIMENTAL)
020public class DmiCabMessage extends CabMessage {
021
022    private final String[] msgArray;
023
024    protected DmiCabMessage(CabMessage msg, Font font){
025        super(msg.getMessageId(), msg.getMessage(), msg.getGroup(), msg.getAckRequired());
026        msgArray = msgs(font );
027    }
028
029    protected String[] getMessageArray(){
030        return java.util.Arrays.copyOf(msgArray, msgArray.length);
031    }
032
033    private String[] msgs( Font font){
034        int maxWidth = 170; // Maximum width in pixels
035        String[] result = splitString(getMessage(), maxWidth, font);
036        log.debug("{} lines in message", result.length);
037        return result;
038    }
039
040    private static String[] splitString(String input, int maxWidth, Font font) {
041        List<String> substrings = new ArrayList<>();
042        StringBuilder currentSubstring = new StringBuilder();
043        String[] words = input.split(" "); // Split input into words
044
045        for (String word : words) {
046            if (currentSubstring.length() == 0) {
047                currentSubstring.append(word);
048            } else {
049                String potentialSubstring = currentSubstring.toString() + " " + word;
050
051                // Check if adding the word exceeds the maximum width
052                if (getStringWidthInPx(potentialSubstring, font) <= maxWidth) {
053                    currentSubstring.append(" ").append(word);
054                } else {
055                    // Current substring exceeds the maximum width, start a new substring
056                    substrings.add(currentSubstring.toString());
057                    currentSubstring = new StringBuilder(word);
058                }
059            }
060        }
061
062        if (currentSubstring.length() > 0) {
063            substrings.add(currentSubstring.toString());
064        }
065        return substrings.toArray(String[]::new);
066    }
067
068    // Function to calculate the width of a string (in pixels)
069    // values should be cached as this is not a fast method.
070    private static int getStringWidthInPx(String input, Font font) {
071
072        JFrame frame = new JFrame();
073        JLabel label = new JLabel(input);
074        label.setFont(font);
075        frame.add(label);
076
077        // Ensure the label is properly sized
078        frame.pack();
079        frame.setVisible(false);
080
081        FontMetrics fontMetrics = label.getFontMetrics(font);
082        int dd = fontMetrics.stringWidth(input);
083
084        frame.dispose(); // Close the frame
085
086        return dd;
087    }
088
089    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DmiCabMessage.class);
090
091}