package eu.mhsl.minenet.minigames.util;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TextUtil {
    public static Component autoWrap(String input, NamedTextColor color) {
        return Component.text(wrap(input, 30, "\n", true, "-", "  "), color);
    }

    public static Component autoWrap(String input) {
        return autoWrap(input, NamedTextColor.WHITE);
    }

    /**
     * Wraps a source String into a series of lines having a maximum specified length.  The source is
     * wrapped at: spaces, horizontal tabs, system newLine characters, or a specified newLine character
     * sequence.  Existing newLine character sequences in the source string, whether they be the system
     * newLine or the specified newLine, are honored.  Existing whitespace (spaces and horizontal tabs)
     * is preserved.
     * <p>
     * When <tt>wrapLongWords</tt> is true, words having a length greater than the specified
     * <tt>lineLength</tt> will be broken, the specified <tt>longWordBreak</tt> terminator appended,
     * and a new line initiated with the text of the specified <tt>longWordLinePrefix</tt> string.  The
     * position of the break will be unceremoniously chosen such that <tt>ineLength</tt> is honored.
     * One use of <tt>longWordLinePrefix</tt> is to effect "hanging indents"  by specifying a series of
     * spaces for this parameter.  This parameter can contain the lineFeed character(s).  Although
     * <tt>longWordLinePrefix</tt> can contain the horizontal tab character, the results are not
     * guaranteed because no attempt is made to determine the quantity of character positions occupied by a
     * horizontal tab.</p>
     * <p>
     * Example usage:
     * <pre>
     * wrap( "  A very long word is Abracadabra in my book", 11, "\n", true, "-", "  ");</pre>
     * returns (note the effect of the single-character lineFeed):
     * <pre>
     *   A very
     * long word
     * is Abraca-
     *   dabra in
     * my book</pre>
     * Whereas, the following:
     * <pre>
     * wrap( "  A very long word is Abracadabra in my book", 11, null, true, null, "  ");</pre>
     * returns (due to the 2-character system linefeed):
     * <pre>
     *   A very
     * long
     * word is A
     *   bracada
     *   bra in
     * my book</pre></p>
     *
     * @param src  the String to be word wrapped, may be null
     * @param lineLength the maximum line length, including the length of <tt>newLineStr</tt> and, when
     *        applicable, <tt>longWordLinePrefix</tt>.  If the value is insufficient to accommodate
     *        these two parameters + 1 character, it will be increased accordingly.
     * @param newLineStr the string to insert for a new line, or <code>null</code> to use the value
     *        reported as the system line separator by the JVM
     * @param wrapLongWords  when <tt>false</tt>, words longer than <tt>wrapLength</t> will not be broken
     * @param longWordBreak string with which to precede <tt>newLineStr</tt> on each line of a broken word,
     *        excepting the last line, or <tt>null</tt> if this feature is not to be used
     * @param longWordLinePrefix string with which to prefix each line of a broken word, subsequent
     *        to the first line, or <tt>null</tt> if no prefix is to be used
     * @return a line with newlines inserted, or <code>null</code> if <tt>src</tt> is null
     */
    private static String wrap(String src, int lineLength, String newLineStr, boolean wrapLongWords, String longWordBreak, String longWordLinePrefix) {
        // Trivial case
        if ( src == null ) return null;

        if ( newLineStr == null )
            newLineStr = System.getProperty( "line.separator" );

        if ( longWordBreak == null )
            longWordBreak = "";

        if ( longWordLinePrefix == null )
            longWordLinePrefix = "";

        // Adjust maximum line length to accommodate the newLine string
        lineLength -= newLineStr.length();
        if ( lineLength < 1 )
            lineLength = 1;

        // Guard for long word break or prefix that would create an infinite loop
        if ( wrapLongWords && lineLength - longWordBreak.length() - longWordLinePrefix.length() < 1 )
            lineLength += longWordBreak.length() + longWordLinePrefix.length();

        int
                remaining = lineLength,
                breakLength = longWordBreak.length();

        Matcher m = Pattern.compile( ".+?[ \\t]|.+?mis" + newLineStr + "singValue|.+?$" ).matcher( src );

        StringBuilder cache = new StringBuilder();

        while ( m.find() ) {
            String word = m.group();

            // Breakup long word
            while ( wrapLongWords && word.length() > lineLength ) {
                cache
                        .append(word, 0, remaining - breakLength)
                        .append( longWordBreak )
                        .append( newLineStr );
                word = longWordLinePrefix + word.substring( remaining - breakLength );
                remaining = lineLength;
            } // if

            // Linefeed if word exceeds remaining space
            if ( word.length() > remaining ) {
                cache
                        .append( newLineStr )
                        .append( word );
                remaining = lineLength;
            } // if

            // Word fits in remaining space
            else
                cache.append( word );

            remaining -= word.length();
        } // while

        return cache.toString();
    } // wrap()

}

