package yem.wm.cm.ht.utils;

import kd.bos.dataentity.utils.StringUtils;

/**
 * 中文汉字和阿拉伯数字相互转化帮助类
 * @author zhangh
 *
 */
public class NumberChineseUtil {
	
	/**
	 * 中文形式，奇数位置是简体，偶数位置是记账繁体，0共用
	 * 使用混合数组提高效率和数组复用
	 **/
	private static final char[] DIGITS = {'零', '一', '壹', '二', '贰', '三', '叁', '四', '肆', '五', '伍',
			'六', '陆', '七', '柒', '八', '捌', '九', '玖'};

	/**
	 * 汉字转阿拉伯数字的
	 */
	private static final ChineseUnit[] CHINESE_NAME_VALUE = {
			new ChineseUnit(' ', 1, false),
			new ChineseUnit('十', 10, false),
			new ChineseUnit('拾', 10, false),
			new ChineseUnit('百', 100, false),
			new ChineseUnit('佰', 100, false),
			new ChineseUnit('千', 1000, false),
			new ChineseUnit('仟', 1000, false),
			new ChineseUnit('万', 1_0000, true),
			new ChineseUnit('亿', 1_0000_0000, true),
	};
	public static final String NULL = "null";
	
	/**
	 * 把中文转换为数字 
	 * @param chinese 中文字符
	 * @return 数字
	 */
	public static int chineseToNumber(String chinese) {
		final int length = chinese.length();
		int result = 0;

		// 节总和
		int section = 0;
		int number = 0;
		ChineseUnit unit = null;
		char c;
		for (int i = 0; i < length; i++) {
			c = chinese.charAt(i);
			final int num = chineseToNumber(c);
			if (num >= 0) {
				if (num == 0) {
					// 遇到零时节结束，权位失效，比如两万二零一十
					if (number > 0 && null != unit) {
						section += number * (unit.value / 10);
					}
					unit = null;
				}
				// 普通数字
				number = num;
			} else {
				unit = chineseToUnit(c);
				if (null == unit) {
					// 出现非法字符
					break;
				}

				//单位
				if (unit.isSecUnit()) {
					// 节单位，按照节求和
					section = (section + number) * unit.getValue();
					result += section;
					section = 0;
				} else {
					// 非节单位，和单位前的单数字组合为值
					int unitNumber = number;
					if (0 == number && 0 == i) {
						// issue#1726，对于单位开头的数组，默认赋予1
						// 十二 -> 一十二
						// 百二 -> 一百二
						unitNumber = 1;
					}
					section += (unitNumber * unit.value);
				}
				number = 0;
			}
		}

		if (number > 0 && null != unit) {
			number = number * (unit.value / 10);
		}

		return result + section + number;
	}

	private static ChineseUnit chineseToUnit(char chinese) {
		for (ChineseUnit chineseNameValue : CHINESE_NAME_VALUE) {
			if (chineseNameValue.name != chinese)
				continue;
			return chineseNameValue;
		}
		return null;
	}

	private static int chineseToNumber(char chinese) {
		if (20004 == chinese) {
			chinese = 20108;
		}

		int i = indexOf(DIGITS, chinese);
		return i > 0 ? (i + 1) / 2 : i;
	}

	/**
	 * 返回数组中指定元素所在位置，未找到返回-1
	 *
	 * @param array 数组
	 * @param value 被检查的元素
	 */
	public static int indexOf(char[] array, char value) {
		if (null != array) {
			for (int i = 0; i < array.length; i++) {
				if (value == array[i]) {
					return i;
				}
			}
		}
		return -1;
	}
	
	/**
	 * 阿拉伯数字转换成中文,小数点后四舍五入保留两位. 使用于整数、小数的转换.
	 *
	 * @param amount           数字
	 * @param isUseTraditional 是否使用繁体
	 * @param isMoneyMode      是否为金额模式
	 */
	public static String format(double amount, boolean isUseTraditional, boolean isMoneyMode) {
		return format(amount, isUseTraditional, isMoneyMode, "负", "元");
	}

	/**
	 * 阿拉伯数字转换成中文.
	 * @param amount           数字
	 * @param isUseTraditional 是否使用繁体
	 * @param isMoneyMode      是否金额模式
	 * @param negativeName     负号转换名称 如：负、(负数)
	 * @param unitName         单位名称 如：元、圆
	 */
	private static String format(double amount, boolean isUseTraditional, boolean isMoneyMode, String negativeName,
			String unitName) {
		if (0 == amount) {
			return "零";
		}
		final StringBuilder chineseStr = new StringBuilder();

		// 负数
		if (amount < 0) {
			chineseStr.append(isNullOrUndefined(negativeName) ? "负" : negativeName);
			amount = -amount;
		}

		long yuan = Math.round(amount * 100);
		final int fen = (int) (yuan % 10);
		yuan = yuan / 10;
		final int jiao = (int) (yuan % 10);
		yuan = yuan / 10;

		// 元
		if (false == isMoneyMode || 0 != yuan) {
			// 金额模式下，无需“零元”
			chineseStr.append(longToChinese(yuan, isUseTraditional));
			if (isMoneyMode) {
				chineseStr.append(isNullOrUndefined(unitName) ? "元" : unitName);
			}
		}

		if (0 == jiao && 0 == fen) {
			//无小数部分的金额结尾
			if (isMoneyMode) {
				chineseStr.append("整");
			}
			return chineseStr.toString();
		}

		// 小数部分
		if (false == isMoneyMode) {
			chineseStr.append("点");
		}

		// 角
		if (0 == yuan && 0 == jiao) {
			// 元和角都为0时，只有非金额模式下补“零”
			if (false == isMoneyMode) {
				chineseStr.append("零");
			}
		} else {
			chineseStr.append(numberToChinese(jiao, isUseTraditional));
			if (isMoneyMode && 0 != jiao) {
				chineseStr.append("角");
			}
		}

		// 分
		if (0 != fen) {
			chineseStr.append(numberToChinese(fen, isUseTraditional));
			if (isMoneyMode) {
				chineseStr.append("分");
			}
		}

		return chineseStr.toString();
	}
	
	/**
	 * 单个数字转汉字
	 * @param number           数字
	 * @param isUseTraditional 是否使用繁体
	 */
	private static char numberToChinese(int number, boolean isUseTraditional) {
		if (0 == number) {
			return DIGITS[0];
		}
		return DIGITS[number * 2 - (isUseTraditional ? 0 : 1)];
	}

	/**
	 * 阿拉伯数字整数部分转换成中文，只支持正数
	 * @param amount           数字
	 * @param isUseTraditional 是否使用繁体
	 */
	private static String longToChinese(long amount, boolean isUseTraditional) {
		if (0 == amount) {
			return "零";
		}

		//将数字以万为单位分为多份
		int[] parts = new int[4];
		for (int i = 0; amount != 0; i++) {
			parts[i] = (int) (amount % 10000);
			amount = amount / 10000;
		}

		final StringBuilder chineseStr = new StringBuilder();
		int partValue;
		String partChinese;

		// 千
		partValue = parts[0];
		if (partValue > 0) {
			partChinese = thousandToChinese(partValue, isUseTraditional);
			chineseStr.insert(0, partChinese);

			if (partValue < 1000) {
				// 和万位之间空0，则补零，如一万零三百
				addPreZero(chineseStr);
			}
		}

		// 万
		partValue = parts[1];
		if (partValue > 0) {
			if ((partValue % 10 == 0 && parts[0] > 0)) {
				// 如果"万"的个位是0，则补零，如十万零八千
				addPreZero(chineseStr);
			}
			partChinese = thousandToChinese(partValue, isUseTraditional);
			chineseStr.insert(0, partChinese + "万");

			if (partValue < 1000) {
				// 和亿位之间空0，则补零，如一亿零三百万
				addPreZero(chineseStr);
			}
		} else {
			addPreZero(chineseStr);
		}

		// 亿
		partValue = parts[2];
		if (partValue > 0) {
			if ((partValue % 10 == 0 && parts[1] > 0)) {
				// 如果"万"的个位是0，则补零，如十万零八千
				addPreZero(chineseStr);
			}

			partChinese = thousandToChinese(partValue, isUseTraditional);
			chineseStr.insert(0, partChinese + "亿");

			if (partValue < 1000) {
				// 和万亿位之间空0，则补零，如一万亿零三百亿
				addPreZero(chineseStr);
			}
		} else {
			addPreZero(chineseStr);
		}

		// 万亿
		partValue = parts[3];
		if (partValue > 0) {
			if (parts[2] == 0) {
				chineseStr.insert(0, "亿");
			}
			partChinese = thousandToChinese(partValue, isUseTraditional);
			chineseStr.insert(0, partChinese + "万");
		}

		if (StringUtils.isNotEmpty(chineseStr) && '零' == chineseStr.charAt(0)) {
			return chineseStr.substring(1);
		}

		return chineseStr.toString();
	}

	private static void addPreZero(StringBuilder chineseStr) {
		if (StringUtils.isEmpty(chineseStr)) {
			return;
		}
		final char c = chineseStr.charAt(0);
		if ('零' != c) {
			chineseStr.insert(0, '零');
		}
	}

	/**
	 * 把一个 0~9999 之间的整数转换为汉字的字符串，如果是 0 则返回 ""
	 *
	 * @param amountPart       数字部分
	 * @param isUseTraditional 是否使用繁体单位
	 */
	private static String thousandToChinese(int amountPart, boolean isUseTraditional) {
		if (amountPart == 0) {
			return String.valueOf(DIGITS[0]);
		}

		int temp = amountPart;
		StringBuilder chineseStr = new StringBuilder();
		boolean lastIsZero = true; // 在从低位往高位循环时，记录上一位数字是不是 0
		for (int i = 0; temp > 0; i++) {
			int digit = temp % 10;
			if (digit == 0) { // 取到的数字为 0
				if (false == lastIsZero) {
					// 前一个数字不是 0，则在当前汉字串前加“零”字;
					chineseStr.insert(0, "零");
				}
				lastIsZero = true;
			} else { // 取到的数字不是 0
				if (String.valueOf(numberToChinese(digit, isUseTraditional)).equals("一") && getUnitName(i, isUseTraditional).equals("十")) {
					chineseStr.insert(0, getUnitName(i, isUseTraditional));
				}else {
					chineseStr.insert(0, numberToChinese(digit, isUseTraditional) + getUnitName(i, isUseTraditional));
				}
				
				lastIsZero = false;
			}
			temp = temp / 10;
		}
		return chineseStr.toString();
	}

	/**
	 * 获取对应级别的单位
	 *
	 * @param index            级别，0表示各位，1表示十位，2表示百位，以此类推
	 * @param isUseTraditional 是否使用繁体
	 */
	private static String getUnitName(int index, boolean isUseTraditional) {
		if (0 == index) {
			return "";
		}
		return String.valueOf(CHINESE_NAME_VALUE[index * 2 - (isUseTraditional ? 0 : 1)].name);
	}

	public static boolean isNullOrUndefined(CharSequence str) {
		if (null == str) {
			return true;
		}
		return isNullOrUndefinedStr(str);
	}

	private static boolean isNullOrUndefinedStr(CharSequence str) {
		String strString = str.toString().trim();
		return NULL.equals(strString) || "undefined".equals(strString);
	}
	
}
