package com.capgemini.framework.common;

import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;

/** Utility class for common String operations. **/
public final class StringHelper {
    private static final int DOT_ZERO_LENGTH = 2;

    /** Empty constant. **/
    public static final String EMPTY = "";

    /** Line feed char constant. **/
    public static final char LINE_FEED = 0x000A;

    /** Tabulation char constant. **/
    public static final String DASH = "-";

    /**
     * Regular expression used for filtering non alpha numerical characters (dot and underscore are authorized).
     **/
    public static final String REGEXP_ALPHANUM = "[^a-zA-Z0-9_.]";

    /** Constructor. **/
    private StringHelper() {
        // Constructor of helper classes must be private
    }

    /**
     * Truncate a string to a specified length.
     * 
     * @param aString String to truncate
     * @param aLength Maximal length of string
     * @return truncated string
     */
    public static String truncate(final String aString, final int aLength) {

        String truncatedString = null;

        // Manage null value
        if (aString != null) {
            if (aString.length() > aLength) {
                truncatedString = aString.substring(0, aLength);
            } else {
                truncatedString = aString;
            }
        }

        return truncatedString;
    }


    /**
     * Merge array elements in a single String.
     * 
     * @param aDelimiter : Delimiter between each element of the array
     * @param aStringArray : Array of string values
     * @return Merged String
     */
    public static String implode(final String aDelimiter, final String... aStringArray) {
        StringBuilder theBuilder = null;
        // Browse array elements for concatenation
        for (String currentString : aStringArray) {
            if (theBuilder == null) {
                theBuilder = new StringBuilder();
            } else {
                // Add separator
                theBuilder.append(aDelimiter);
            }
            // Add next element
            theBuilder.append(currentString == null ? "null" : currentString);
        }
        // By default return an empty string
        if (theBuilder == null) {
            return EMPTY;
        }
        return theBuilder.toString();
    }

    /**
     * Merge array elements in a single String.
     * 
     * @param aDelimiter : Delimiter between each element of the array
     * @param aStringArray : Array of string values
     * @return Merged String
     */
    public static String implodeList(final String aDelimiter, final Collection<?> aStringArray) {
        StringBuilder theBuilder = null;

        // Browse array elements for concatenation
        for (Object obj : aStringArray) {

            if (theBuilder == null) {
                theBuilder = new StringBuilder();
            } else {
                // Add separator
                theBuilder.append(aDelimiter);
            }
            // Add next element
            theBuilder.append(obj == null ? "null" : obj.toString());
        }

        // By default return an empty string
        if (theBuilder == null) {
            return EMPTY;
        }

        return theBuilder.toString();
    }

    /**
     * String concatenation of multiple strings.
     * 
     * @param aStringArray Array of value which must be concatenated
     * @return Concatenated value in a String
     */
    public static String concatToString(final String... aStringArray) {
        return concat(aStringArray).toString();
    }

    /**
     * String concatenation of multiple strings.
     * 
     * @param aStringArray Array of value which must be concatenated
     * @return Concatenated value in a StringBuilder
     */
    public static StringBuilder concat(final String... aStringArray) {
        StringBuilder theBuilder = new StringBuilder();
        for (String currentValue : aStringArray) {
            theBuilder.append(currentValue);
        }
        return theBuilder;
    }

    /**
     * Fill value with 0 to format a string number Example: 1 converted to 4 digits => "0001".
     * 
     * @param aValue integer value
     * @param aDigitCount digit size
     * @return Formated string with the expected digits count
     */
    public static String fixedDigits(final double aValue, final int aDigitCount) {

        String theStringConvertion = String.valueOf(aValue);
        if (theStringConvertion.endsWith(".0")) {
            theStringConvertion = truncate(theStringConvertion, theStringConvertion.length() - DOT_ZERO_LENGTH);
        }
        StringBuilder theStringBuilder = new StringBuilder(theStringConvertion);

        /* Zero fill */
        int missing0 = aDigitCount - theStringBuilder.length();
        if (missing0 > 0) {
            String insertion = truncate("0000000000000000", missing0);
            theStringBuilder.insert(0, insertion);
        }

        return theStringBuilder.toString();
    }

    /**
     * Javascript code conversion for attributes of the current bean.
     * 
     * @param aJsArrayName Name of the javascript array
     * @param aJavaBean Serialized JAVA bean
     * @return JS code.
     */
    public static String toJs(final String aJsArrayName, final Object aJavaBean) {

        StringBuilder theJsCode = new StringBuilder(aJsArrayName).append(" = new Array();\n");
        Map<String, String> theAttMap = BeanHelper.toStringMap(aJavaBean);
        for (Entry<String, String> currentEntry : theAttMap.entrySet()) {

            /* Avoid quotes or line feed in displayable content */
            String theJsValue = currentEntry.getValue();
            theJsValue = StringHelper.toHtml(theJsValue);

            /* Compute the JS code for current attribute */
            StringBuilder currentAtt = concat(aJsArrayName, "['", currentEntry.getKey(), "']='", theJsValue, "';\n");

            /* Append to attribute list */
            theJsCode.append(currentAtt);
        }

        return theJsCode.append(LINE_FEED).toString();
    }

    /**
     * Replace String values with the HTML format.
     * 
     * @param anHtmlCode String to convert
     * @return HTML code with entities
     */
    public static String toHtml(final String anHtmlCode) {
        String filtered = anHtmlCode.replace("'", "&#39;");
        filtered = filtered.replace("\"", "&quote;");
        filtered = filtered.replace("\n", "<br/>");
        return filtered;
    }

    /**
     * If the input is null, returns "". Otherwise, return the input.
     * @param input the input String
     * @return a never-null String
     */
    public static String replaceNullByEmpty(String input) {
        return input == null ? EMPTY : input;
    }

    /**
     * Split a string to an array from a pattern delimiter in parameter, and not return delimiter as a token.
     * 
     * @param delimiter a delimiter for the successive splits
     * @param value a full sentence to splits
     * @return string array
     */
    public static String[] splitWithoutDelim(final String delimiter, final String value) {
        StringTokenizer tokens = new StringTokenizer(value, delimiter, false);
        String[] result = new String[tokens.countTokens()];
        int tokenCount = 0;
        while (tokens.hasMoreTokens()) {
            result[tokenCount] = tokens.nextToken();
            tokenCount++;
        }
        return result;
    }
}
