/**
 * $Id$
 * Copyright(C) 2015-2020 kowlone - internet center, All Rights Reserved.
 */
package com.liquidnet.commons.lang.util;

import com.liquidnet.commons.lang.CommonConst;
import org.slf4j.helpers.MessageFormatter;

import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

/**
 * 字符串工具类
 *
 * @author <a href="kowlone2006@163.com">kowlone</a>
 * @version 1.0 2012-4-20 上午2:13:53
 */
public abstract class StringUtil {
    /**
     * 随机数对象
     */
    private static final Random random = new Random();
    /**
     * 数字与字母字典
     */
    private static final char[] LETTER_AND_DIGIT = ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
    /**
     * 数字与字母字典长度
     */
    private static final int LETTER_AND_DIGIT_LENGTH = LETTER_AND_DIGIT.length;
    /** 使用Log4j2的消息格式化工厂 */


    /**
     * 检测字符串是否为空字符串
     * 字符串为空的标准：null或全部由空字符组成的字符串
     *
     * @param str 待检测字符串
     * @return <li>true：字符串是空字符串</li>
     * <li>false：字符串不是空字符串</li>
     */
    public static boolean isEmpty(String str) {
        return (str == null || str.trim().length() == 0);
    }


    /**
     * 检测字符串是否为空字符串
     * 字符串为空的标准：null或全部由空字符组成的字符串
     *
     * @param obj 待检测字符串
     * @return <li>true：字符串是空字符串</li>
     * <li>false：字符串不是空字符串</li>
     */
    public static boolean isEmpty(Object obj) {

        return (obj == null || obj.toString().trim().length() == 0);

    }

    /**
     * 检测字符串是否不为空字符串
     * 字符串为空的标准：null或全部由空字符组成的字符串
     *
     * @param str 待检测字符串
     * @return <li>true：字符串不是空字符串</li>
     * <li>false：字符串是空字符串</li>
     * @see #isEmpty(String)
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * 将对象转换为字符串
     *
     * @param input 待转换对象
     * @return 转换后的字符串
     * @see #getString(Object, String)
     * @see #getString(String)
     * @see #getString(String, String)
     * @see CommonConst#DFT_STRING_VAL
     */
    public static String getString(Object input) {
        return getString(input, CommonConst.DFT_STRING_VAL);
    }

    /**
     * 将对象转换为字符串
     *
     * @param input  待转换对象
     * @param defVal 对象转换为空字符串时的默认返回值
     * @return 转换后的字符串
     * @see #getString(String)
     * @see #getString(String, String)
     */
    public static String getString(Object input, String defVal) {
        return (input == null) ? defVal : getString(input.toString(), defVal);
    }

    /**
     * 转换字符串
     *
     * @param input 待转换字符串
     * @return 转换后的字符串
     * @see #getString(String, String)
     */
    public static String getString(String input) {
        return getString(input, CommonConst.DFT_STRING_VAL);
    }

    /**
     * 转换字符串
     *
     * @param input  待转换字符串
     * @param defVal 默认转换值
     * @return 转换后的字符串
     * <li>字符串为null或全部由空白字符组成的字符串时，返回defVal参数指定的值</li>
     * <li>其他情况，返回去掉字符串两端空白字符后的字符串</li>
     */
    public static String getString(String input, String defVal) {
        return (isEmpty(input)) ? defVal : input.trim();
    }

    /**
     * 生成固定长度的随机字符串
     *
     * @param len 随机字符串长度
     * @return 生成的随机字符串
     */
    public static String getRandomString(final int len) {
        if (len < 1) {
            return "";
        }
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            sb.append(LETTER_AND_DIGIT[random.nextInt(LETTER_AND_DIGIT_LENGTH)]);
        }
        return sb.toString();
    }

    /**
     * 生成固定长度的随机字符串
     *
     * @param len        随机字符串长度
     * @param dictionary 字符串字典
     * @return 生成的随机字符串
     */
    public static String getRandomString(final int len, char[] dictionary) {
        if (len < 1) {
            return "";
        }
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            sb.append(dictionary[random.nextInt(dictionary.length)]);
        }
        return sb.toString();
    }

    /**
     * 创建一个新的字符串
     *
     * @param bytes 字符串内容字节数组(UTF-8编码)
     * @return 新创建的字符串
     * @see #newString(byte[], String)
     */
    public static String newString(byte[] bytes) {
        return newString(bytes, CommonConst.DFT_CHARSET);
    }

    /**
     * 创建一个新的字符串
     *
     * @param bytes   字符串内容字节数组
     * @param charset 字符串字节编码
     * @return 新创建的字符串
     */
    public static String newString(byte[] bytes, String charset) {
        try {
            return new String(bytes, charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("不支持的字符集：" + charset, e);
        }
    }

    /**
     * 取得字符串字节数组
     *
     * @param str 字符串
     * @return 字符串内容字节数组
     * @see #getBytes(String, String)
     */
    public static byte[] getBytes(String str) {
        return getBytes(str, CommonConst.DFT_CHARSET);
    }

    /**
     * 取得字符串字节数组
     *
     * @param str     字符串
     * @param charset 字符串字节编码
     * @return 字符串内容字节数组
     */
    public static byte[] getBytes(String str, String charset) {
        if (str == null) {
            return null;
        }
        try {
            return str.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("不支持的字符集：" + charset, e);
        }
    }

    /**
     * 从右侧开始截取固定长度的字符串
     *
     * @param str    待截取字符串
     * @param length 截取的长度
     * @return <li>null：字符串为空或字符串长度小于截取的长度</li>
     * <li>非null：截取字符串后的结果</li>
     */
    public static String right(String str, int length) {
        return (str == null || str.length() < length) ? null : str.substring(str.length() - length);
    }

    /**
     * 从左侧开始截取固定长度的字符串
     *
     * @param str    待截取字符串
     * @param length 截取的长度
     * @return <li>null：字符串为空或字符串长度小于截取的长度</li>
     * <li>非null：截取字符串后的结果</li>
     */
    public static String left(String str, int length) {
        return (str == null || str.length() < length) ? null : str.substring(0, length);
    }

    /**
     * 截取定长字符串（中文、字符、字母、数字……）
     *
     * @param str
     * @param fixedWidth
     * @return
     */
    public static String subFixedWidthString(String str, int fixedWidth) {
        if (str.length() <= fixedWidth) {
            return str;
        } else {
            StringBuilder ret = new StringBuilder();
            fixedWidth = fixedWidth << 1;
            int currentWidth = 0;
            for (int i = 0; i < str.length(); i++) {
                char ch = str.charAt(i);
                currentWidth += (ch < 128) ? 1 : 2;
                if (currentWidth > fixedWidth) {
                    break;
                }
                ret.append(ch);
            }
            ret.append("…");
            return ret.toString();
        }
    }


    /**
     * 将数组中字符串按照分隔符连接成一个字符串
     *
     * @param seperator 分隔符
     * @param params    待连接字符串数组
     * @return 连接后的字符串
     */
    public static String join(String seperator, Object... params) {
        return joinArray(seperator, params);
    }

    /**
     * 将数组中字符串按照分隔符连接成一个字符串
     *
     * @param seperator 分隔符
     * @param params    待连接字符串数组
     * @return 连接后的字符串
     */
    public static String joinArray(String seperator, Object[] params) {
        if (params == null || params.length == 0) {
            return CommonConst.DFT_STRING_VAL;
        }

        StringBuilder ret = new StringBuilder();
        for (Object param : params) {
            if (param == null) {
                continue;
            }
            if (ret.length() > 0) {
                ret.append(seperator);
            }
            if (param.getClass().isArray()) {
                ret.append(joinArray(seperator, (Object[]) param));
            } else {
                ret.append(param);
            }
        }
        return ret.toString();
    }

    /**
     * 比较两个字符串大小
     *
     * @param str1 字符串1
     * @param str2 字符串2
     * @return <li>-1：str1小</li>
     * <li>0：两字符串相等</li>
     * <li>1：str2小</li>
     */
    public static int compare(String str1, String str2) {
        if (str1 == null && str2 == null) {
            return 0;
        }
        if (str1 == null) {
            return -1;
        }
        if (str2 == null) {
            return 1;
        }

        int len1 = str1.length();
        int len2 = str2.length();
        int len = Math.min(len1, len2);
        for (int i = 0; i < len; i++) {
            char ch1 = str1.charAt(i);
            char ch2 = str2.charAt(i);
            if (ch1 == ch2) {
                continue;
            }
            return (ch1 < ch2) ? -1 : 1;
        }

        if (len1 == len2) {
            return 0;
        }
        return (len1 < len2) ? -1 : 1;
    }

    /**
     * 根据参数填充占位符,构建字符串消息,例如:
     * msg=我是{} params:小明 返回值为:我是小明
     *
     * @param message
     * @param params
     * @return
     */
    public static String buildMessage(String message, Object... params) {
//		return messageFactory.newMessage(msg,params).getFormattedMessage();
        if (params != null) {
            message = MessageFormatter.arrayFormat(message, params).getMessage();
        }
        return message;
    }

    /**
     * 过滤空格
     *
     * @param str 待过滤字符串
     * @return 过滤结果
     */
    public static String trim(String str) {
        return str == null ? null : str.trim();
    }

    /**
     * 将字符串指定索引位的字符转换为大写
     *
     * @param source
     * @param index
     * @return
     */
    public static String toUpperCase(String source, int index) {
        char[] chars = source.toCharArray();
        chars[index] = Character.toUpperCase(chars[index]);
        return new String(chars);
    }


    // GENERAL_PUNCTUATION 判断中文的“号
    // CJK_SYMBOLS_AND_PUNCTUATION 判断中文的。号
    // HALFWIDTH_AND_FULLWIDTH_FORMS 判断中文的，号
    public static final boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
            return true;
        }
        return false;
    }


    public static final boolean isChinese(String strName) {
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            char c = ch[i];
            if (isChinese(c)) {
                return true;
            }
        }
        return false;
    }

    public static final boolean isMobile(String str) {
        Pattern pattern = Pattern.compile("^[1][3,4,5,7,8][0-9]{9}$"); // 验证手机号
        Matcher matcher = pattern.matcher(str);
        boolean b = matcher.matches();
        return b;
    }

    public static final boolean isEmail(String str) {
        String paString = "^([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)*@([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)+[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$";
        Pattern pattern = Pattern.compile(paString); // 验证邮箱
        Matcher matcher = pattern.matcher(str);
        boolean b = matcher.matches();
        return b;
    }

    public static String hiddenName(String name) {
        if (isEmpty(name)) {
            return "";
        }

        if (name.length() <= 2) {
            return name.charAt(0) + "*";
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(name.charAt(0));
            IntStream.range(0, name.length() - 2).forEach(s -> sb.append("*"));
            sb.append(name.charAt(name.length() - 1));
            return sb.toString();
        }
    }

    public static String hiddenMobile(String mobile) {
        return left(mobile, 3) + "****" + right(mobile, 4);
    }

    public static String hiddenIDCardNumber(String idcardNumber) {
        if (isEmpty(idcardNumber)) {
            return "";
        }

        if (idcardNumber.length() <= 15) {
            return left(idcardNumber, 4) + "******" + right(idcardNumber, 5);
        } else {
            return left(idcardNumber, 2) + "****" + idcardNumber.substring(6, 8) + "******" + right(idcardNumber, 4);
        }
    }

    public static String hiddenBankId(String bankId) {
        if (isEmpty(bankId)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(left(bankId, 4));
        IntStream.range(0, bankId.length() - 8).forEach(s -> sb.append("*"));
        sb.append(right(bankId, 4));
        return sb.toString();
    }


    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs != null && (strLen = cs.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }

    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

    public static String andStartTime(String start) {
        return start + " 00:00:00";
    }

    public static String andEndTime(String end) {
        return end + " 23:59:59";
    }


    public static String chineseName(String fullName) {
        if (org.apache.commons.lang3.StringUtils.isBlank(fullName)) {
            return "";
        }
        String name = org.apache.commons.lang3.StringUtils.left(fullName, 1);
        return org.apache.commons.lang3.StringUtils.rightPad(name, org.apache.commons.lang3.StringUtils.length(fullName), "*");
    }

    /**
     * * 判断一个对象是否为空
     *
     * @param object Object
     * @return true：为空 false：非空
     */
    public static boolean isNull(Object object) {
        return object == null;
    }

    /**
     * * 判断一个对象是否非空
     *
     * @param object Object
     * @return true：非空 false：空
     */
    public static boolean isNotNull(Object object) {
        return !isNull(object);
    }

    /**
     * * 判断一个对象数组是否为空
     *
     * @param objects 要判断的对象数组
     *                * @return true：为空 false：非空
     */
    public static boolean isEmpty(Object[] objects) {
        return isNull(objects) || (objects.length == 0);
    }

    /**
     * * 判断一个对象数组是否非空
     *
     * @param objects 要判断的对象数组
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Object[] objects) {
        return !isEmpty(objects);
    }

    /**
     * * 判断一个Collection是否为空， 包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Collection<?> coll) {
        return isNull(coll) || coll.isEmpty();
    }

    /**
     * * 判断一个Collection是否非空，包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (str != null && strs != null) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 字符串位置交换
     *
     * @param p1 位置1
     * @param p2 位置2
     * @return 交换位置大于字符长度返回原字符。小于返回交换后结果
     */
    public static String switchPosition(String str, int p1, int p2) {
        if (str.length() < p1 + 1 || str.length() < p2 + 1) {
            return str;
        }
        char[] charArray = str.toCharArray();
        char temp = charArray[p1];
        charArray[p1] = charArray[p2];
        charArray[p2] = temp;
        return String.valueOf(charArray);
    }

    public static void main(String[] args) {
        System.out.println(isEmail("123@qq.com#$%^&*()"));

        String regEx = "[\n`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。， 、？]";

        //可以在中括号内加上任何想要替换的字符，实际上是一个正则表达式

        String aa = "";//这里是将特殊字符换为aa字符串," "代表直接去掉

        Pattern p = Pattern.compile(regEx);

        Matcher m = p.matcher("原字符串");//这里把想要替换的字符串传进来

        String newString = m.replaceAll(aa).trim();
        System.out.println("newString=====" + newString);

        //将替换后的字符串存在变量newString中

        //方法二 如果第一种太麻烦可以直接用下面的

        String str = "#$%^&*()我的正确#$%^&*()原字符串#$%^&*()";

        String newString2 = str.replaceAll(regEx, aa).trim();//不想保留原来的字符串可以直接写成 “str = str.replaceAll(regEX,aa);”
        System.out.println("newString2=====" + newString2);

    }
}
