package org.jboss.installer.common;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Insets;
import java.util.Locale;

/**
 * Created by dsoukhov on 16/03/17.
 */
public class WidthWrappingTextMessagePane extends JTextArea {
    private final Locale locale;
    private int width;
    private FontMetrics fm;

    public WidthWrappingTextMessagePane(String msg, int maxWidth, Font font, Locale locale) {
        this.fm = this.getFontMetrics(font);
        this.locale = locale;

        setEditable(false);
        setFocusable(false);
        setBackground(null);
        setFont(font);

        int textWidth = getMessageWidth(msg);
        if (textWidth > maxWidth) {
            setWrapStyleWord(true);
            setLineWrap(true);
            setMargin(new Insets(2, 0, 2, 0));

            width = maxWidth;
            setPreferredSize(new Dimension(width, getPreferredSize().height * rowCountWrapLine(msg)));
        }

        setText(msg);
    }

    @Override
    protected int getColumnWidth() {
        return getAdjustedColumnWidth(this, locale);
    }

    /**
     * Returns a more correct columnWidth for layout manager use, based on the language being used.
     * This resolves JBEAP-15209 and JBEAP-15210.
     * <p>
     * The problem is exhibited when the user's locale is zh_CN.UTF-8 or ja_JP.UTF-8. The default font used (at least
     * on Fedora 28) reports a width of '7' for the character 'm'. This means that the point at which the text wraps
     * is incorrectly calculated.
     *
     * @return width of a single column within the JTextField, adjusting to specific languages
     */
    public static int getAdjustedColumnWidth(JComponent component, Locale locale) {
        JComponent existingComponent = component != null ? component : new JLabel();
        String iso3lang = locale.getISO3Language();
        FontMetrics fm = existingComponent.getFontMetrics(existingComponent.getFont());
        if (iso3lang.equals("chn") || iso3lang.equals("jpn")) {
            // '木' is used because it appears in both Chinese and Japanese
            return fm.charWidth('木');
        } else {
            return fm.charWidth('m');
        }
    }

    private int getMessageWidth(String msg){
        int max = 0;
        String[] lines = msg.split("\\n");

        if(lines.length == 1)return fm.stringWidth(msg);

        //if contains newline textWidth is the largest string segment
        for(String line:lines) {
            max = max < fm.stringWidth(line) ? fm.stringWidth(line): max;
        }
        return max + fm.stringWidth("\\n");
    }

    private int rowCountWrapLine(String text){
        int rowCount = 1;
        int widthCount = 0;

        String[] words = text.split("(?<=\\s)");

        if(words.length == 1) return rowCount + rowCountWrapWord(words[0]);

        for(int i =0; i < words.length-1; i++) {
            String word = words[i];
            String nextWord = words[i+1];
            if(fm.stringWidth(word) > width) {
                rowCount += rowCountWrapWord(word);
                widthCount = fm.stringWidth(word) % width;
            } else {
                widthCount += fm.stringWidth(word);
                int remainder = width - widthCount;

                //increment row count if there is no room left on current row or if word has a newline char
                if (remainder < fm.stringWidth(nextWord) ||word.contains("\n")){
                    rowCount++;
                    widthCount = 0;
                }
            }
        }
        String finalWord = words[words.length-1];
        if(fm.stringWidth(finalWord) > width) rowCount += rowCountWrapWord(finalWord);
        return rowCount;
    }


    private int rowCountWrapWord(String word){
        int additionalRows = 0;
        int widthCount = 0;

        char[] letters = word.toCharArray();

        for(int i =0; i < letters.length-1; i++) {
            char curChar = letters[i];
            char nextChar = letters[i+1];
            widthCount += fm.charWidth(curChar);
            int remainder = width - widthCount;

            if (remainder < fm.charWidth(nextChar)) {
                additionalRows++;
                widthCount = 0;
            }
        }
        return additionalRows;
    }
}
