/**
 * Baidu.com,Inc.
 * Copyright (c) 2000-2013 All Rights Reserved.
 */
package com.baidu.hsb.route.util;

import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Pattern;
import java.util.zip.CRC32;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

/**
 * 
 * @author [email protected]
 * @version $Id: StringUtil.java, v 0.1 2013年12月21日 下午6:26:43 HI:brucest0078 Exp $
 */
public class StringUtil extends StringUtils {

    /** 判断字符串是否为16进制数字 */
    public static final Pattern HAX_PATTERN = Pattern.compile("^[0-9a-fA-F]+$");

    /** 判断字符串是否为数字 */
    public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]+$");

    /** 默认中文编码字符集 */
    public static final String DEFAULT_CHINESE_CHARSET = "GBK";

    public static final String LINE_END = System.getProperty("line.separator");

    /**
     * 扩展并左对齐字符串,用指定字符串填充右边。 新增对中文字符串的支持,注意方法名称为<code>alignLeft<b>s</b></code>
     * 
     * <pre>
     * StringUtil.alignLeft(null, *, *)      = null
     * StringUtil.alignLeft("", 3, "z")      = "zzz"
     * StringUtil.alignLeft("bat", 3, "yz")  = "bat"
     * StringUtil.alignLeft("bat", 5, "yz")  = "batyz"
     * StringUtil.alignLeft("bat", 8, "yz")  = "batyzyzy"
     * StringUtil.alignLeft("bat", 1, "yz")  = "bat"
     * StringUtil.alignLeft("bat", -1, "yz") = "bat"
     * StringUtil.alignLeft("bat", 5, null)  = "bat  "
     * StringUtil.alignLeft("bat", 5, "")    = "bat  "
     * StringUtil.alignLeft("中文", 5, "")    = "中文 "
     * </pre>
     *
     * @param str 要对齐的字符串
     * @param size 扩展字符串到指定宽度
     * @param padStr 填充字符串
     *
     * @return 扩展后的字符串,如果字符串为<code>null</code>,则返回<code>null</code>
     */
    public static String alignLefts(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }

        String padStringFinal = (isEmpty(padStr)) ? EMPTY : padStr;
        int padLen = padStringFinal.length();
        int strLen = str.getBytes().length;
        int pads = size - strLen;

        if (pads <= 0) {
            return str;
        }

        if (pads == padLen) {
            return str.concat(padStringFinal);
        } else if (pads < padLen) {
            return str.concat(padStringFinal.substring(0, pads));
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStringFinal.toCharArray();

            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }

            return str.concat(new String(padding));
        }
    }

    /**
     * 扩展并右对齐字符串,用指定字符串填充左边。 新增对中文字符串的支持,注意方法名称为<code>alignRight<b>s</b></code>
     * 
     * <pre>
     * StringUtil.alignRight(null, *, *)      = null
     * StringUtil.alignRight("", 3, "z")      = "zzz"
     * StringUtil.alignRight("bat", 3, "yz")  = "bat"
     * StringUtil.alignRight("bat", 5, "yz")  = "yzbat"
     * StringUtil.alignRight("bat", 8, "yz")  = "yzyzybat"
     * StringUtil.alignRight("bat", 1, "yz")  = "bat"
     * StringUtil.alignRight("bat", -1, "yz") = "bat"
     * StringUtil.alignRight("bat", 5, null)  = "  bat"
     * StringUtil.alignRight("bat", 5, "")    = "  bat"
     * StringUtil.alignRight("中文", 5, "")    = " 中文"
     * </pre>
     *
     * @param str 要对齐的字符串
     * @param size 扩展字符串到指定宽度
     * @param padStr 填充字符串
     *
     * @return 扩展后的字符串,如果字符串为<code>null</code>,则返回<code>null</code>
     */
    public static String alignRights(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }

        String padStringFinal = (isEmpty(padStr)) ? EMPTY : padStr;
        int padLen = padStringFinal.length();
        int strLen = str.getBytes().length;
        int pads = size - strLen;
        if (pads <= 0) {
            return str;
        }

        if (pads == padLen) {
            return padStringFinal.concat(str);
        } else if (pads < padLen) {
            return padStringFinal.substring(0, pads).concat(str);
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStringFinal.toCharArray();

            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }

            return new String(padding).concat(str);
        }
    }

    /**
     * 取指定字符串的子串,新增对中文字符串的支持 注意方法名称为<code>substring<b>s</b></code>
     *
     * @param str 字符串
     * @param start 起始索引,如果为负数,表示从尾部计算
     * @param end 结束索引(不含),如果为负数,表示从尾部计算
     *
     * @return 子串,如果原始串为<code>null</code>,则返回<code>null</code>
     */
    public static String substrings(String str, int start, int end) {
        if (str == null) {
            return null;
        }

        int length = end - start;
        byte[] dest = new byte[length];
        System.arraycopy(str.getBytes(), start, dest, 0, length);

        return new String(dest);
    }

    /**
     * 根据长度<code>length</code>把字符串切成两段,保存数组<br>
     * 确保中文不要被切成两半
     * 
     * @param message
     * @param length
     * @return
     */
    public static String[] cutString(String message, int length) {
        String normal = StringUtil.substrings(message, 0, length);
        if (isContainChinese(message, length)) {
            normal = StringUtil.substrings(message, 0, length - 1);
        }

        return new String[] { normal, StringUtil.substringAfter(message, normal) };
    }

    /**
     * 字符串是否包含中文
     * 
     * @param message
     * @param length
     * @return
     */
    public static boolean isContainChinese(String message) {
        char[] chars = message.toCharArray();
        byte[] bytes;
        try {
            bytes = message.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            bytes = message.getBytes();
        }
        return (chars.length != bytes.length);
    }

    /**
     * 字符串起始长度<code>length</code>的字符串是否包含中文
     * 
     * @param message
     * @param length
     * @return
     */
    public static boolean isContainChinese(String message, int length) {
        char[] chars = StringUtil.substrings(message, 0, length).toCharArray();
        char[] charsPlus = StringUtil.substrings(message, 0, length + 1).toCharArray();
        return ArrayUtils.isSameLength(chars, charsPlus);
    }

    /**
     * 在字符串中查找指定字符集合中的字符,并返回第一个匹配的起始索引。 如果字符串为<code>null</code>,则返回<code>-1</code>。 如果字符集合为<code>null</code>或空,也返回
     * <code>-1</code>。
     * 
     * <pre>
     * StringUtil.indexOfAny(null, *,0)                = -1
     * StringUtil.indexOfAny("", *,0)                  = -1
     * StringUtil.indexOfAny(*, null,0)                = -1
     * StringUtil.indexOfAny(*, [],0)                  = -1
     * StringUtil.indexOfAny("zzabyycdxx",['z','a'],0) = 0
     * StringUtil.indexOfAny("zzabyycdxx",['b','y'],0) = 3
     * StringUtil.indexOfAny("aba", ['z'],0)           = -1
     * </pre>
     *
     * @param str 要扫描的字符串
     * @param searchChars 要搜索的字符集合
     * @param startPos 开始搜索的索引值,如果小于0,则看作0
     *
     * @return 第一个匹配的索引值。如果字符串为<code>null</code>或未找到,则返回<code>-1</code>
     */
    public static int indexOfAny(String str, char[] searchChars, int startPos) {
        if ((str == null) || (str.length() == 0) || (searchChars == null) || (searchChars.length == 0)) {
            return -1;
        }

        for (int i = startPos; i < str.length(); i++) {
            char ch = str.charAt(i);

            for (int j = 0; j < searchChars.length; j++) {
                if (searchChars[j] == ch) {
                    return i;
                }
            }
        }

        return -1;
    }

    /**
     * 过滤要输出到json的字符串,将'和"进行转义输出
     * 
     * @param input
     * @return
     */
    public static String filterJsonString(String input) {
        if (input == null) {
            return EMPTY;
        }
        int length = input.length();
        StringBuilder result = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            char c = input.charAt(i);
            switch (c) {
                case '\'': {
                    result.append("\\'");
                    break;
                }
                case '\"': {
                    result.append("\\\"");
                    break;
                }
                default: {
                    result.append(c);
                }
            }
        }
        return result.toString();
    }

    /**
     * 过滤要输出到xml的字符串,将<,>,&,"进行转义输出
     * 
     * @param string
     * @return
     */
    public static String filterXMLString(String input) {
        if (input == null) {
            return EMPTY;
        }
        int length = input.length();
        StringBuilder result = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            char c = input.charAt(i);
            switch (c) {
                case '<': {
                    result.append("&lt;");
                    break;
                }
                case '>': {
                    result.append("&gt;");
                    break;
                }
                case '\"': {
                    result.append("&uot;");
                    break;
                }
                case '&': {
                    result.append("&amp;");
                    break;
                }
                default: {
                    result.append(c);
                }
            }
        }
        return result.toString();
    }

    /**
     * 根据url获取系统名称 如果url里面包括系统名就返回,否则直接返回域名 如http://bops.alipay.com 返回bops http://www.alipay.com 返回 alipay.com
     * 
     * @param url
     * @return
     * @throws MalformedURLException
     */
    public static String getSystemNameByURL(String url) throws MalformedURLException {
        URL netURL = new URL(url);
        String domain = netURL.getHost();
        if (domain.startsWith("www.")) {
            domain = domain.substring(5);
        }
        int offset = domain.indexOf("alipay");
        if (offset > 0) {
            return domain.substring(0, offset - 1);
        } else {
            return domain;
        }
    }

    /**
     * 获取指定字符串按GBK编码转换成的byte长度 由于String.getByte方法依赖于操作系统编码,处理中文字符串时建议用此方法
     * 
     * @param data
     * @return
     */
    public static byte[] getGBKByte(String data) {
        if (data == null) {
            return new byte[0];
        }
        try {
            return data.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            return data.getBytes();
        }
    }

    /**
     * 获取指定字符串按GBK编码转换成byte的长度 由于String.getByte方法依赖于操作系统编码,处理中文字符串时建议用此方法
     * 
     * @param data
     * @return
     */
    public static int getGBKByteLength(String data) {
        return getGBKByte(data).length;
    }

    /**
     * 生成一定长度的序列号
     * 
     * @param length
     * @param padding
     * @return
     */
    public static String genSerialNo(int length, String padding) {
        String nanoTime = System.nanoTime() + "";
        if (nanoTime.length() >= length) {
            nanoTime = nanoTime.substring(0, length);
        } else {
            nanoTime = nanoTime + repeat(padding, length - nanoTime.length());
        }
        return nanoTime;
    }

    /**
     * 将数字格式化到固定长度
     * 
     * @param input
     * @param fixLength
     * @return
     */
    public static String formatNumberToFixedLength(String input, int fixLength) {
        if (input.length() <= fixLength) {
            // 未到指定长度,左补0
            return StringUtils.leftPad(input, fixLength, '0');
        } else {
            // 超过长度,砍掉左边超长部分
            return input.substring(input.length() - fixLength);
        }
    }

    /**
     * 判断字符串是否为16进制数字
     * 
     * @param input
     * @return
     */
    public static boolean isHexString(String input) {
        if (input == null) {
            return false;
        }
        if (NUMBER_PATTERN.matcher(input).matches()) {
            // 过滤掉纯数字
            return false;
        }
        return HAX_PATTERN.matcher(input).matches();
    }

    /**
     * 获取换行符(\n),供vm中使用,屏蔽了操作系统的差异
     * 
     * @return
     */
    public static String getNewLine() {
        return LINE_END;
    }

    /**
     * 将byte[]按指定编码转换为字符串,供velocity中使用
     * 
     * @param bytes
     * @param charsetName
     * @return
     */
    public static String getNewString(byte[] bytes, String charsetName) {
        try {
            return new String(bytes, charsetName);
        } catch (UnsupportedEncodingException e) {
            return EMPTY;
        }
    }

    public static String crc32(String str) {
        CRC32 crc32 = new CRC32();
        crc32.update(str.getBytes());
        return crc32.getValue() + "";
    }

    public static String o2Str(Object o) {
        if (o == null) {
            return null;
        }
        return defaultIfBlank(o.toString(), EMPTY);
    }

    public static void main(String[] args) {
        // System.out.println(substring(crc32("123123123123123"), -3, -1));
        String s = "<person>121212:/aaa/bbb";
        VelocityContext context = new VelocityContext();
        Writer writer = new StringWriter();
        // //Pattern.compile("^[0-9a-fA-F]+$")
        Velocity.evaluate(context, writer, StringUtil.EMPTY, "$!Pattern.compile(\"^[0-9a-fA-F]+$\")");
        System.out.println(writer.toString());

        System.out.println(substring(s, s.indexOf(">") + 1, s.indexOf(":")));
        // $!stringUtil.substring($PARENT_PATH, $!stringUtil.indexOf($PARENT_PATH,">") + 1,
        // $!stringUtil.indexOf($PARENT_PATH,":"))
        // $!stringUtil.substring
    }

}