package gov.va.med.fw.util;

import gov.va.med.fw.service.InvalidArgumentException;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This helper class is intended to be used by tags and decryption filter to encrypt and decrypt the information.
 *
 * @author Muddaiah Ranga
 * @version 3.0
 */
public class StringUtils extends org.apache.commons.lang.StringUtils
{
    private static final char AMPERSAND = '&';
    private static final char SEMICOLON = ';';
    public static final char ZERO = '0';

    private static final Map replacementMap = new HashMap();

    private static Pattern pattern;
	private static Matcher matcher;

	protected transient static Log logger = LogFactory.getLog(StringUtils.class.getName());

    static
    {
        replacementMap.put("amp", "&");
        replacementMap.put("gt", ">");
        replacementMap.put("lt", "<");
        replacementMap.put("quot", "\"");
        replacementMap.put("#39", "\\");
    }

    /**
     * Replaces the following string. "&amp;"  -> '&' "&gt;"   -> '>' "&lt;"   -> '<' "&quot;" -> '"' "&#39;"  -> '\'
     *
     * @param pString the string to work on
     *
     * @return string after all the entities replaced
     */
    public static String replaceHtmlEntities(String pString)
    {
        StringBuffer sb = new StringBuffer();
        int base = 0;
        int index = base;
        while ((index = pString.indexOf(AMPERSAND, base)) >= base)
        {
            sb.append(pString.substring(base, index));
            int index2 = pString.indexOf(SEMICOLON, index);
            if (index2 != -1 && (index2 - index < 8))
            {
                String token = pString.substring(index + 1, index2);
                String replacement = (String)replacementMap.get(token);
                if (replacement != null)
                {
                    sb.append(replacement);
                }
                else
                {
                    sb.append(AMPERSAND);
                    sb.append(token);
                    sb.append(SEMICOLON);
                }
                base = index2 + 1;
            }
            else
            {
                sb.append(AMPERSAND);
                base = index + 1;
            }
        }
        sb.append(pString.substring(base));
        return sb.toString();
    }

    public static boolean contains(String[] strings, String string)
    {
        if (strings == null) return false;
        for (int i = 0; i < strings.length; i++)
        {
            if (StringUtils.equals(strings[i], string))
                return true;
        }
        return false;
    }

    /**
     * Return true if the given string starts with any of the strings in the given array.
     * @param string - string to compare
     * @param strings - array of strings to comare start with.
     * @return True if the given string starts with the specified strings or false if not.
     */
    public static boolean startsWith(String string, String[] strings)
    {
        if (string == null || strings == null) return false;
        for (int i = 0; i < strings.length; i++)
        {
            if (string.startsWith(strings[i]))
                return true;
        }
        return false;
    }

    /**
     * Utility method: Generate string representation of a Collection
     */
    public static String stringFor(Collection pList, String pListName)
    {
        final StringBuffer sb = new StringBuffer();
        if (pListName != null)
        {
            sb.append(pListName);
            sb.append("=");
        }

        if (pList != null)
        {
            sb.append("{");
            final Iterator iter = pList.iterator();
            while (iter.hasNext())
            {
                Object value = iter.next();

                if (value instanceof Map)
                {
                    sb.append(stringFor((Map)value, "map"));
                }
                else
                    if (value instanceof Collection)
                    {
                        sb.append(stringFor((Collection)value, "coll"));
                    }
                    else
                    {
                        sb.append(value);
                    }

                if (iter.hasNext())
                {
                    sb.append(",");
                }
            }
            sb.append("}");
        }
        else
        {
            sb.append("null");
        }
        return sb.toString();
    }

    /**
     * Utility method: Generate string representation of a Map
     */
    public static String stringFor(Map pMap, String pMapName)
    {
        final StringBuffer sb = new StringBuffer();
        if (pMapName != null)
        {
            sb.append(pMapName);
            sb.append("=");
        }

        if (pMap != null)
        {
            sb.append("{");

            Set mapSet = pMap.entrySet();
            Iterator iter = mapSet.iterator();
            while (iter.hasNext())
            {
                Map.Entry entry = (Map.Entry)iter.next();
                sb.append("(");
                sb.append(entry.getKey());
                sb.append("=");
                Object value = entry.getValue();
                if (value instanceof Map)
                {
                    sb.append(stringFor((Map)value, "map"));
                }
                else
                    if (value instanceof Collection)
                    {
                        sb.append(stringFor((Collection)value, "coll"));
                    }
                    else
                    {
                        sb.append(value);
                    }
                sb.append(")");

                if (iter.hasNext())
                {
                    sb.append(",");
                }
            }

            sb.append("}");
        }
        else
        {
            sb.append("null");
        }
        return sb.toString();

    }

    public static String keepAlphaAndHyphen(String string)
    {
        StringBuffer cleanString = new StringBuffer();
        if (StringUtils.isNotEmpty(string))
        {
            for (int i = 0; i < string.length(); i++)
            {
                if (Character.isLetter(string.charAt(i)) || string.charAt(i) == '-')
                {
                    cleanString.append(string.charAt(i));
                }
            }
        }
        return cleanString.toString();
    }

    /**
     * Compares the first string to the second string.  The null string will be treated as the empty string.
     * @param string1 The first string to compare
     * @param string2 The second string to compare
     * @return the comparrison result.
     */
    public static int compareTo(String string1, String string2)
    {
        if (string1 == null)
        {
            string1 = "";
        }
        if (string2 == null)
        {
            string2 = "";
        }
        return string1.compareTo(string2);
    }

    /**
     * Returns true if all the chars in a given string are same,
     * false otherwise.
     * If input string is null, return false.
     * If input string is empty (0 length), return true.
     * @param string - input string to validate
     * @return true|false
     */
    public static boolean isSameCharString(String string) {
        if (string != null) {
            for (int i = 1; i < string.length(); i++) {
                if (string.charAt(i-1) != string.charAt(i)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Returns the number of times a character is present in a string.
     * @param stringToCompare The string.
     * @param matchString The string to search for.
     * @return The number of time the string is present.  0 is returned for null or the emptry string.
     */
    public static int numTimesStringPresent(String stringToCompare, String matchString)
    {
        // Handle the empty string by returning 0.
        if ((StringUtils.isEmpty(stringToCompare)) || (StringUtils.isEmpty(matchString)))
        {
            return 0;
        }

        // Initialize our counter and the compare buffer
        int count=0;
        StringBuffer compareBuffer = new StringBuffer(stringToCompare);

        // Keep looping until the compare buffer is empty
        while (compareBuffer.length() > 0)
        {
            // Search for the match string in the buffer
            int index = compareBuffer.indexOf(matchString);
            if (index == -1)
            {
                // We didn't find a match so empty out the string to exit our loop
                compareBuffer.setLength(0);
            }
            else
            {
                // We found a match so increment our counter and remove everything up to and including the match
                // from the compare buffer.
                count++;
                compareBuffer.delete(index, index + matchString.length());
            }
        }

        // Return the count
        return count;
    }

    /**
     * Left pads the value string with 0s up to the desiredLength
     * @return Returns the value left padded with 0s.
     */
    public static String leftPadWithZero(String value, int desiredLength) throws InvalidArgumentException
    {
        String paddedValue = null;
        String strippedValue = stripToNull(value);

        if(!StringUtils.isEmpty(strippedValue))
        {
            paddedValue = leftPad(strippedValue, desiredLength, ZERO);
        }
        else
        {
        	if( logger.isErrorEnabled() ) {
                logger.debug( "Invalid argument to left pad with zeros");
             }
        	throw new InvalidArgumentException("Invalid argument to left pad with zeros: ", null);
        }

        return paddedValue;
    }

    /**
     * Truncates a string to the desiredLength.
     * @return Returns the string with only desiredLength characters.
     */
    public static String truncToMaxLength(String value, int desiredLength)
    {
        if(!StringUtils.isEmpty(value) && value.length() > desiredLength)
        {
            return value.substring(0, desiredLength);
        }
        else
        {
            return value;
        }
    }

    public static boolean containsNumbers(String str){

    	if (str == null || StringUtils.isEmpty(str)) return false;
    	for (int i = 0; i < str.length(); i++) {
    		if (Character.isDigit(str.charAt(i)))
    	        return true;
    	}
    	return false;
    }

    /**
	   * Validate component name with regular expression
	   * @param name component name for validation
	   * @param name_pattern regex pattern to be used for validation
	   * @return true valid name, false invalid name
	   */
	  public static boolean validateEntry(String name, String name_pattern){
		  pattern = Pattern.compile(name_pattern);
		  matcher = pattern.matcher(name);
		  return matcher.matches();

	  }


}
