/*
 * Copyright (c) 2004-2017, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package lc.mecha.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This utility class provides helpful methods for working with
 * <code>String</code>s.
 *
 * @author Alex Leigh
 */

public class StringUtil {
    private static Pattern squareBracketPattern = Pattern.compile("\\[([^]]*)]");
    public static final String NULL_STR = "";

    public static String addLinebreaks(String input, int maxLineLength) {
        StringTokenizer tok = new StringTokenizer(input, " ");
        StringBuilder output = new StringBuilder(input.length());
        int lineLen = 0;
        while (tok.hasMoreTokens()) {
            String word = tok.nextToken();

            if (lineLen + word.length() > maxLineLength) {
                output.append("\n");
                lineLen = 0;
            }
            output.append(word);
            lineLen += word.length();
        }
        return output.toString();
    }

    /**
     * Make a {@link List} of strings for every blank string in the provided <code>array</code>.
     */
    public static List<String> makeList(String[] array) {
        ArrayList<String> lst = new ArrayList<>();
        for (String s : array) {
            if (!s.isEmpty()) lst.add(s);
        }
        return lst;
    }

    public static String removePrefix(String str, String prefix) {
        if (str.startsWith(prefix)) {
            return str.substring(prefix.length());
        }

        return str;

    }

    /**
     * Return a string consisting of every character before the first instance of the given character.
     */

    public static String firstPart(String s, String delim) {
        if (s == null) return null;
        String split[] = s.split(delim);
        return split[0];
    }

    public static boolean safeEquals(final String a, final String b) {
        return a == null && b == null || !(a == null || b == null) && a.equals(b);
    }

    /**
     * Return the provided string, or <code>"(null)"</code> if the provided string was null.
     */
    public static String safeString(String v1) {
        return v1 == null ? NULL_STR : v1;
    }

    public static void addToList(final List<String> list, final String... values) {
        list.addAll(Arrays.asList(values));
    }

    /**
     * Returns a version of the provided string with the first character of the
     * string converted to title case (upper case).
     *
     * @param str
     * @return
     */
    public static String capitalize(final String str) {
        if (str == null || (str.length()) == 0) {
            return str;
        }
        return String.valueOf(Character.toTitleCase(str.charAt(0))) + str.substring(1);
    }

    /**
     * This method performs a <code>toLowerCase</code> operation on the first character of the provided
     * string, returning the result.
     *
     * @param str
     * @return
     */
    public static String decapitalize(final String str) {
        if (str == null || (str.length()) == 0) {
            return str;
        }
        return String.valueOf(Character.toLowerCase(str.charAt(0))) + str.substring(1);
    }

    /**
     * Returns the length of the <code>String</code> (ie, s.length()). Returns 0 if the
     * parameter is null, which is why you would use this method at all.
     * <p>
     * This code is equal to <code>(s==null?0:s.length())</code>.
     */
    public static int length(final String s) {
        return s == null ? 0 : s.length();
    }

    public static String quoteSafe(final String value) {
        final StringBuilder sb = new StringBuilder();
        final int len = value.length();
        for (int i = 0; i < len; i++) {
            final char c = value.charAt(i);
            switch (c) {
                case '\\':
                    sb.append("\\\\");
                    break;
                case '\"':
                    sb.append("\\\"");
                    break;

                default:
                    sb.append(c);
                    break;
            }
        }
        return sb.substring(0);
    }

    /**
     * Strip all whitespace and alpha characters from the string, returning only
     * numeric character. eg "foo 123 bar 456" becomes "123456"
     */
    public static String stripAlpha(final String s) {
        return s.replaceAll("[^0-9]", "");
    }

    public static String makeCamelCase(final String dirty) {
        final StringBuilder result = new StringBuilder(dirty.length());
        final String strl = dirty.toLowerCase();
        boolean bMustCapitalize = false;
        for (int i = 0; i < strl.length(); i++) {
            final char c = strl.charAt(i);
            if (c >= 'a' && c <= 'z') {
                if (bMustCapitalize) {
                    result.append(strl.substring(i, i + 1).toUpperCase());
                    bMustCapitalize = false;
                } else {
                    result.append(c);
                }
            } else {
                bMustCapitalize = true;
            }
        }
        return result.toString();
    }

    /**
     * Return the last part of a value that may contain a delimiter.
     *
     * @param value
     * @param regex
     * @return
     */
    public static String last(final String value, final String regex) {
        final String[] v = value.split(regex);
        if (v.length == 0) return value;
        return v[v.length - 1];
    }

    /**
     * Returns the first instance of a string contained within square brackets, or null if no
     * such string is found.
     */
    public static String findInSquareBrackets(final CharSequence value) {
        Matcher m = squareBracketPattern.matcher(value);
        if (m.find()) {
            return m.group(1);
        }
        return null;
    }

    public static String stringOrBlank(String s1) {
        if (s1 == null) return "";
        return s1;
    }

    /**
     * Converts the given object to a string, unless it is null, in which case, null is returned. This differentiates
     * it from String.valueOf().
     */
    public static String valueOf(Object s) {
        if (s == null) return null;
        return s.toString();
    }
}
