package com.qmth.qrzk.repository.utils;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.zip.ZipFile;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.DateUtil;

import com.qmth.qrzk.repository.utils.docx.DocxReader;

/**
 * 
* ClassName：General   
* Description:主要工具类 包含大部分常用函数
* author：chengsonglin   
* createdate：2014-2-11     
* @version    
*
 */
public class General {
	
	/**
	 * 临时文件夹路径，系统加载时会判断此路径是否存在，如果不存在，自动创建之。
	 * @author 马涛 2014-09-29
	 */
	public static String TEMPORARY_DIR_PATH = null;
	static{
		try {
			Properties prop = new Properties();
			prop.load(General.class.getResourceAsStream("/qrzk.conf"));
			TEMPORARY_DIR_PATH = prop.getProperty("TemporaryDirPath");
			File dir = new File(TEMPORARY_DIR_PATH);
			if (dir.exists() && !dir.isDirectory()) {
				throw new Exception(dir.getPath() + "不是文件夹！");
			}
			if(!dir.exists()){
				dir.mkdirs();
			}
		} catch (Exception e) {
			System.err.println("加载配置文件文件[qrzk.conf]失败，原因：" + e.getMessage());
			e.printStackTrace();
			throw new RuntimeException("加载配置文件文件[qrzk.conf]失败，原因：" + e.getMessage(),e);
		}
	}

	/**
	 * 判断字符串是否为空
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(String str) {
		return (str == null || "".equals(str)) ? true : false;
	}

	/**
	 * 判断字符串是否不为空
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNotEmpty(String str) {
		return (str == null || "".equals(str)) ? false : true;
	}

	/**
	 * 判断是否为数字
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str) {
		try {
			Integer.parseInt(str);
			return true;
		} catch (Exception ex) {
			return false;
		}
	}

	/**
	 * 将null转换为空字符串
	 * 
	 * @param str
	 * @return
	 */
	public static String convertNullToEmpty(String str) {
		return str == null ? "" : str;
	}

	/**
	 * 替换字符串
	 * 
	 * @param src
	 *            源字符串
	 * @param oldstr
	 *            要替换的字符串
	 * @param newstr
	 *            新字符串
	 * @return
	 */
	public static String replace(String src, String oldstr, String newstr) {
		StringBuffer dest = new StringBuffer();
		int beginIndex = 0;
		int endIndex = 0;
		while (true) {
			endIndex = src.indexOf(oldstr, beginIndex);
			if (endIndex >= 0) {
				dest.append(src.substring(beginIndex, endIndex));
				dest.append(newstr);
				beginIndex = endIndex + oldstr.length();
			} else {
				dest.append(src.substring(beginIndex));
				break;
			}
		}
		return dest.toString();
	}

	/**
	 * HTML字符串编码
	 * 
	 * @param str
	 * @return
	 */
	public static String HTMLEncode(String str) {
		if (str != null) {
			str = replace(str, "\\", "&#92;");
			str = replace(str, "'", "&#39;");
			str = replace(str, "\"", "&quot;");
			str = replace(str, "<", "&lt;");
			str = replace(str, ">", "&gt;");
			str = replace(str, "<<", "&raquo;");
			str = replace(str, ">>", "&laquo;");
			str = replace(str, "'", "");
			str = replace(str, "\"", "");
			str = replace(str, "\r\n", "\n");
			str = replace(str, "\n", "<br>");
			str = replace(str, "  ", "　");
			str = replace(str, "&", "&amp;");
			str = replace(str, "&amp;amp;", "&amp;");
			str = replace(str, "&amp;quot;", "&quot;");
			str = replace(str, "&amp;lt;", "&lt;");
			str = replace(str, "&amp;gt;", "&gt;");
			str = replace(str, "&amp;nbsp;", "&nbsp;");
		}
		return str;
	}

	/**
	 * 
	 * @param str
	 * @return
	 */
	
	
	public static String removeXss(String str) {
		if (str != null) {
			str = replace(str, "\\","");
			str = replace(str, "'", "");
			str = replace(str, "\"","");
			str = replace(str, "<", "");
			str = replace(str, ">", "");
			str = replace(str, "<<","");
			str = replace(str, ">>"," ");
			str = replace(str, "'", "");
			str = replace(str, "\"", "");
			str = replace(str, "\r\n","");
			str = replace(str, "\n", "");
			str = replace(str, "  ", "");
			str = replace(str, "&", "");
			str = replace(str, "&amp;amp;", "");
			str = replace(str, "&amp;quot;", "");
			str = replace(str, "&amp;lt;", "");
			str = replace(str, "&amp;gt;", "");
			str = replace(str, "&amp;nbsp;", "");
		}
		return str;
	}
	
	
	/**
	 * HTML字符串解码
	 * 
	 * @param str
	 * @return
	 */
	public static String HTMLDecode(String str) {
		if (str != null) {
			str = replace(str, "<br>", "\r\n");
		}
		return str;
	}

	/**
	 * 防止SQL注入
	 * 
	 * @param str
	 * @return
	 */
	public static String sqlStr(String str) {
		if (str != null) {
			str = replace(str, "'", "");
			str = replace(str, " ", "");
			str = replace(str, "\\", "&#92;");
		}
		return str;
	}

	/**
	 * 获取当前时间
	 * 
	 * @return yyyy-MM-dd HH:mm:ss
	 */
	public static String getNow() {
		SimpleDateFormat formatter = new SimpleDateFormat(Consts.EXCEL_DATE_FORMAT_STR0);
		Date date = new Date();
		return formatter.format(date);
	}
	
	/**
	 * 格式化时间，返回格式化后的时间字符串
	 * @param date
	 * @param formatPattern
	 * @return
	 */
	public static String formatDate(Date date,String formatPattern){
		SimpleDateFormat formatter = new SimpleDateFormat(formatPattern);
		return formatter.format(date);
	}
	
	/**
	 * 按照标准的yyyy-MM-dd HH:mm:ss来格式化时间
	 * @param date
	 * @return
	 */
	public static String formatDate(Date date){
		return formatDate(date,Consts.EXCEL_DATE_FORMAT_STR0);
	}

	/**
	 * 依据格式获取当前时间
	 * 
	 * @param format
	 * @return
	 */
	public static String getNow(String format) {
		SimpleDateFormat formatter = new SimpleDateFormat(format);
		Date date = new Date();
		return formatter.format(date);
	}

	/**
	 * 日期计算
	 * 
	 * @param day
	 * @return
	 */
	public static String addDays(int day) {
		SimpleDateFormat formatter = new SimpleDateFormat(Consts.EXCEL_DATE_FORMAT_STR0);
		Calendar right = Calendar.getInstance();
		right.add(Calendar.DAY_OF_MONTH, day);
		Date date = right.getTime();
		return formatter.format(date);
	}

	/**
	 * 自定义日期格式的日期计算
	 * 
	 * @param day
	 * @param format
	 * @return
	 */
	public static String addDays(int day, String format) {
		SimpleDateFormat formatter = new SimpleDateFormat(format);
		Calendar right = Calendar.getInstance();
		right.add(Calendar.DAY_OF_MONTH, day);
		Date date = right.getTime();
		return formatter.format(date);
	}

	/**
	 * 用指定分隔符分隔字符串
	 * 
	 * @param str
	 * @param separator
	 * @return
	 */
	public static List<String> segmentationStr(String str, String separator) {
		List<String> result = new ArrayList<String>();
		if (General.isEmpty(str))
			return result;
		StringTokenizer token = new StringTokenizer(str, separator);
		while (token.hasMoreElements()) {
			result.add(token.nextToken());
		}
		return result;
	}

	/**
	 * URL编码方法
	 * 
	 * @param url
	 * @param encode
	 *            字符集 默认为UTF-8
	 * @return
	 */
	public static String encodeURL(String url, String encode) {
		if (General.isEmpty(encode))
			encode = "utf8";
		try {
			return java.net.URLEncoder.encode(url, encode);
		} catch (UnsupportedEncodingException e) {
			return url;
		}
	}

	/**
	 * URL解码方法
	 * 
	 * @param url
	 * @param decode
	 *            字符集 默认为UTF-8
	 * @return
	 */
	public static String decodeURL(String url, String decode) {
		String u = url;
		if (General.isEmpty(decode))
			decode = "utf8";
		try {
			u = java.net.URLDecoder.decode(url, decode);
		} catch (Exception e) {
			return url;
		}
		return u;
	}

	/**
	 * 判断字符串是否为合法手机号 11位 13 15 18开头
	 * 
	 * @param str
	 * @return boolean
	 */
	public static boolean isMobile(String str) {
		if (General.isEmpty(str))
			return false;
		return str.matches("^(13|15|18)\\d{9}$");
	}

	/**
	 * 判断是否为正确的邮件格式
	 * 
	 * @param str
	 * @return boolean
	 */
	public static boolean isEmail(String str) {
		if (General.isEmpty(str))
			return false;
		return str.matches("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$");
	}

	public static boolean isPhone(String str) {
		if (General.isEmpty(str))
			return false;
		return str
				.matches("^((\\(\\d{3}\\))|(\\d{3}\\-))?(\\(0\\d{2,3}\\)|0\\d{2,3}-)?[1-9]\\d{6,7}$");
	}

	/**
	 * 取得指定位数随机数
	 * 
	 * @param n
	 *            指定位数
	 * @return
	 */
	public static String getRandom(int n) {
		String[] seed = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
		StringBuffer sb = new StringBuffer(n);
		for (int i = 0; i < n; i++) {
			sb.append(seed[(int) (Math.random() * 10)]);
		}
		return sb.toString();
	}

	/**
	 * URL参数编码
	 * 
	 * @param url
	 * @return
	 */
	public static String encodeURLParam(String url, String charset) {
		int rex = url.indexOf("=");
		if (rex == -1)
			return url;

		StringBuffer sb = new StringBuffer();
		List<String> list = General.segmentationStr(url, "=");
		for (int i = 0; i < list.size(); i++) {
			String temp = list.get(i);
			if (i == 0)
				sb.append(temp).append("=");
			else {
				if (temp.indexOf("&") == 0) {
					sb.append(temp).append("=");
				} else if (temp.indexOf("&") == -1)
					sb.append(General.encodeURL(temp, charset));
				else {
					sb.append(
							General.encodeURL(
									temp.substring(0, temp.indexOf("&")),
									charset)).append(
							temp.substring(temp.indexOf("&")));
					sb.append("=");
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 全角字符转半角
	 * 
	 * @param str
	 * @return
	 */
	public static String converFullStr(String str) {
		char[] c = str.toCharArray();
		for (int i = 0; i < c.length; i++) {
			if (c[i] == 12288) {
				c[i] = (char) 32;
				continue;
			}
			if (c[i] > 65280 && c[i] < 65375)
				c[i] = (char) (c[i] - 65248);
		}
		return new String(c);
	}

	/**
	 * 去除字符串中的HTML代码
	 * 
	 * @param str
	 * @return
	 */
	public static String removeHTMLCode(String str) {
		if (General.isEmpty(str))
			return "";
		StringBuffer sb = new StringBuffer(str);
		try {
			while (sb.indexOf("<") != -1 && sb.indexOf(">") != -1
					&& sb.indexOf("<") < sb.indexOf(">") + 1) {
				sb.delete(sb.indexOf("<"), sb.indexOf(">") + 1);
			}
		} catch (Exception ex) {
			System.out.println(sb.length());
			System.out.println(sb.indexOf("<"));
			System.out.println(sb.indexOf(">") + 1);
			ex.printStackTrace();
			return "";
		}
		return sb.toString();
	}
	
	/**
	 * 去除含有html脚本的参数
	 * @param str
	 * @return
	 */
	public static String removeHtml(String str){
		 String htmlStr = str; //含html标签的字符串 	  
		 String textStr =""; 	      
		 java.util.regex.Pattern p_script; 	    
		 java.util.regex.Matcher m_script; 	     
		 java.util.regex.Pattern p_style; 	 
		 java.util.regex.Matcher m_style; 	
	     java.util.regex.Pattern p_html; 	 
	     java.util.regex.Matcher m_html; 	
     try { 	      
    	 String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; //定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script> } 	 
    	 String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; //定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style> } 	        
    	 String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式 	      	   
    	 p_script = Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE); 	    
    	 m_script = p_script.matcher(htmlStr); 	       
    	 htmlStr = m_script.replaceAll(""); //过滤script标签 		     
    	 p_style = Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE); 	 
    	 m_style = p_style.matcher(htmlStr); 	 
    	 htmlStr = m_style.replaceAll(""); //过滤style标签 	      
    	 p_html = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE); 	
    	 m_html = p_html.matcher(htmlStr); 	   
    	 htmlStr = m_html.replaceAll(""); //过滤html标签 	       
    	 /* 空格 ——   */	         // 
    	 p_html = Pattern.compile("\\ ", Pattern.CASE_INSENSITIVE);	       
    	 m_html = p_html.matcher(htmlStr);	     
    	 htmlStr = htmlStr.replaceAll(" "," ");	     
    	 textStr = htmlStr; 	      	     
    	 }catch(Exception e) { 
    		 e.printStackTrace();
    	 } 	    
    	 return textStr.replace(">", "").replace("<", "");
     }

	/**
	 * 获取能兼容发布路径：“”、“/”、“/qrzk”、“/qrzk/”的应用上下文路径。只要保证应用上下文路径不是以“/”结尾就可以了
	 * @param request
	 * @return 不以“/”结尾的应用上下文路径，例如：“”、“/qrzk”
	 */
	public static String getBasePath(HttpServletRequest request){
		String basePath = request.getContextPath();
//		System.out.println("basePath=" + basePath);
		if(basePath.endsWith("/")){
			basePath = basePath.substring(0, basePath.lastIndexOf('/'));
		}
		return basePath;
	}

	/**
	 * 根据字段名获取对应的get方法，例如name对应的get方法：getName
	 * @param property
	 * @return
	 */
	public static String getterMethodName(String property){
		return "get"+property.substring(0,1).toUpperCase()+property.substring(1); 
	}
	
	public static void close(ResultSet rst){
		if(rst != null){
			try {
				rst.close();
			} catch (Exception e) {
				System.err.println(e.getMessage());
			}
		}
	}
	
	public static void close(Statement pst){
		if(pst != null){
			try {
				pst.close();
			} catch (Exception e) {
				System.err.println(e.getMessage());
			}
		}
	}
	
	public static void close(Connection conn){
		if(conn != null){
			try {
				conn.close();
			} catch (Exception e) {
				System.err.println(e.getMessage());
			}
		}
	}

	public static void close(InputStream is) {
		if (is != null) {
			try {
				is.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void close(OutputStream os) {
		if (os != null) {
			try {
				os.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void close(ZipFile zipFile) {
		if (zipFile != null) {
			try {
				zipFile.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void delete(File file){
		if(file != null){
			try {
				FileUtils.forceDelete(file);
			} catch (Exception e) {
				System.err.println("无法删除文件(夹)：" + file.getPath() + "，请手动删除!");
				e.printStackTrace();
			}
		}
	}
	
	public static void delete(DocxReader docxReader){
		if(docxReader != null){
			docxReader.releaseTemporaries();
		}
	}
	
	/**
	 * <p>
	 * 把select SQL语句转换成count SQL语句，例如select * from t_user u where u.type=? order by u.name，转成
	 * SELECT COUNT(1) FROM t_user u where u.type=?
	 * </p>
	 * <b>注意：</b>
	 * <p>
	 * 1.不支持直接union的SQL语句，例如：select a.* from AAA a union select b.* from BBB b，
	 * 但支持这样的SQL语句，例如：select c.* from (select a.* from AAA a union select b.* from BBB b) c；
	 * </p>
	 * <p>
	 * 2.不支持直接DISTINCT的SQL语句，例如：select DISTINCT a.* from AAA a，
	 * 但支持这样的SQL语句：select b.* from (select DISTINCT a.* from AAA a) b
	 * </p>
	 * @author 马涛
	 * @param sql
	 * @return
	 */
	public static String toCountSql(String sql){
		sql = sql.trim().replace('\n', ' ').replace('\t', ' ');
		while(sql.contains("  ")){
			sql = sql.replace("  ", " ");
		}
		List<Integer> selectList = new ArrayList<Integer>();//采用select-from栈方式查找第一个select对应的from
		String fromPart = sql.substring("select ".length());//默认开头就是select字符串，在selectList栈中放入一个标识，同时字符串截取掉select部分
		selectList.add(1);
		{//去掉末尾的order by部分
			int orderIndex = fromPart.toLowerCase().indexOf(" order by ");
			if(orderIndex > 0){
				fromPart = fromPart.substring(0, orderIndex);
			}
		}
		while(true){
			int selectIndex = fromPart.toLowerCase().indexOf(" select ");
			if(selectIndex == -1){
				selectIndex = fromPart.toLowerCase().indexOf("(select ");
			}
			int fromIndex = fromPart.toLowerCase().indexOf(" from ");
			if(selectIndex > -1 && selectIndex < fromIndex){
				selectList.add(1);
				fromPart = fromPart.substring(selectIndex + " select ".length());
			}else{
				selectList.remove(selectList.size() -1);
				fromPart = fromPart.substring(fromIndex + " from ".length());
			}
			if(selectList.size() == 0){
				break;
			}
		}
		String newSql = "SELECT COUNT(1) FROM " + fromPart;
		return newSql;
	}
	  
	/**
	 * 将数字转化为汉字的数组,因为各个实例都要使用所以设为静态
	 */
	private static final char[] cnLowerNumbers={'零','一','二','三','四','五','六','七','八','九'};
	  
	/**
	 * 供分级转化的数组,因为各个实例都要使用所以设为静态
	 */
	private static final char[] series={'十','百','千','万','十','百','千','亿'};
	
	/**
	 * 阿拉伯数字转成中文的数字，不涉及金额数字的处理。TODO 有一些Bug，对100,1001类似的特殊数字没有处理好。
	 * 现在100以内的数字或者中间不带0的数字转换没有问题。
	 * <b>*不支持负数</b>
	 * @param num 阿拉伯数据
	 * @return 中文数字
	 */
	public static String toCNNum(int num){
		if(num == 0){
			return cnLowerNumbers[0] + "";
		}
		if(num < 0){
			throw new RuntimeException("不支持负数");
		}
		// 成员变量初始化
		String integerPart = "" + num;
		

		// 因为是累加所以用StringBuffer
		StringBuffer sb = new StringBuffer();

		// 整数部分处理
		for (int i = 0; i < integerPart.length(); i++) {
			int number = getNumber(integerPart.charAt(i));

			sb.append(cnLowerNumbers[number]);
			if(integerPart.length() - 2 - i >= 0){
				sb.append(series[integerPart.length() - 2 - i]);
			}
		}
		String cnNum = sb.toString();
		if(cnNum.startsWith("一十")){
			cnNum = cnNum.substring(1);
		}
		while(cnNum.endsWith("" + cnLowerNumbers[0])){
			cnNum = cnNum.substring(0,cnNum.length()-1);
		}

		// 返回拼接好的字符串
		return cnNum;
	}
	
	/**
	 * 将字符形式的数字转化为整形数字 因为所有实例都要用到所以用静态修饰
	 * 
	 * @param c
	 * @return
	 */
	private static int getNumber(char c) {
		String str = String.valueOf(c);
		return Integer.parseInt(str);
	}
	
	/**
	 * 生成不带“-”的UUID字符串
	 * @return
	 */
	public static String generalUUID(){
		return UUID.randomUUID().toString().replace("-", "");
	}
	
	/**
	 * 格式化分数，数字后面没有0的时候就不要出现0
	 * @param score
	 * @return
	 */
	public static String formatScore(double score){
		DecimalFormat df = new DecimalFormat("#.##");
		return df.format(score);
	}

	public static String getCellTextForShow(HSSFCell cell){
		if(cell == null){
			return Consts.NULL_STR;
		}
		switch (cell.getCellType()) {
			case HSSFCell.CELL_TYPE_BLANK:
				return Consts.NULL_STR;
				
			case HSSFCell.CELL_TYPE_BOOLEAN:
				return trim2Str(cell.getBooleanCellValue(), Consts.NULL_STR);
				
			case HSSFCell.CELL_TYPE_FORMULA:
				return trim2Str(cell.getNumericCellValue(), Consts.NULL_STR);
				
			case HSSFCell.CELL_TYPE_NUMERIC:
				if(DateUtil.isCellDateFormatted(cell)) {
					return formatDate(cell.getDateCellValue(), Consts.EXCEL_DATE_FORMAT_STR1);
		        }else {
		        	BigDecimal value = new BigDecimal(cell.getNumericCellValue());
		        	return trim2Str(value, Consts.NULL_STR);
		        }
				
			case HSSFCell.CELL_TYPE_STRING:
				return trim2Str(cell.getStringCellValue(), Consts.NULL_STR);
				
			default:
				return Consts.UNKOWN_STR;
		}
	}
	
	public static final String trim2Str(Object str,String defaultValue){
		if(str == null){
			return defaultValue;
		}
		String str2 = null;
		if(str instanceof String){
			str2 = ((String)str).trim();
		}else{
			str2 = str.toString().trim();
		}
		return str2.length() == 0 ? defaultValue:str2;
	}

	public static int toInteger(Object obj, int defaultValue) {
		try {
			return (int) toDouble(obj,defaultValue);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	public static double toDouble(Object obj, double defaultValue) {
		if (obj == null) {
			return defaultValue;
		}
		if (obj instanceof Integer) {
			return (Integer) obj;
		}
		if (obj instanceof Float) {
			return (Float) obj;
		}
		if (obj instanceof Double) {
			return (Double) obj;
		}
		try {
			return Double.parseDouble(obj.toString());
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 把行、列的index值转成Excel坐标
	 * 
	 * @param rowIndex 行序列值，从0开始计数
	 * @param colIndex 列序列值，从0开始计数
	 * @return
	 */
	public static String toExcelCoordinate(int rowIndex, int colIndex) {
		char A = 'A';
		int m = colIndex / 26;
		String priStr = m == 0 ? "" : (((char) (A + (m - 1))) + "");
		colIndex = colIndex % 26;
		String colStr = ((char) (A + colIndex)) + "";
		return priStr + colStr + (rowIndex + 1);
	}
}
