package com.huigou.uasp.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.collections.MapUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.Assert;

import com.google.common.base.CaseFormat;

import com.huigou.data.exception.SQLParseException;
import com.huigou.data.jdbc.util.ParseSQLParam;
import com.huigou.data.query.model.QueryModel;
import com.huigou.exception.ApplicationException;
import com.huigou.util.ClassHelper;
import com.huigou.util.LogHome;
import com.huigou.util.StringUtil;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Transient;

public class ComUtils {
	protected static final Pattern pattern = Pattern.compile("\t|\r|\n"); //去除制表符、换行符
	private static final int  BUFFER_SIZE = 2 * 1024;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
	/**
	 * 
	 * @author zq
	 * @date 2018年7月27日
	 * @return
	 * @Description TODO(自动生成uuid)
	 */
	public static String createUuid() {
		UUID u = UUID.randomUUID();
		String uuid = u.toString().replace("-", "").toUpperCase();
		return uuid;
	}
	
	
	//解析sql
	private static ParseSQLParam getParseSqlParam(String sql, Map<String, Object> param) throws SQLParseException{
	    ParseSQLParam parser = new ParseSQLParam();
	    parser.parse(sql);
	    List<String> names = parser.getParameter();
	    Object obj = null;
	    for (Object name : names) {
	    obj = param.get(name);
	       if (obj == null) {
	       throw new SQLParseException("未找到参数:" + name + " 对应的数据！");
	 }
	 parser.addValue(obj);
	 }
	 return parser;
	}

	private static String toSqlString(String sql, Object[] args) throws ApplicationException {
		  String str = sql;
		try {
		  if (args != null)
		     for (int i = 0; i < args.length; ++i)
		    	 try {
		            str = str.replaceFirst("\\?", "'" + args[i] + "'");
		          } catch (PatternSyntaxException e) {
		            e.printStackTrace();
		           }
		     }
		     catch (Exception e)
		     {
		       LogHome.getLog().error(e);
		    }
		    Matcher matcher = pattern.matcher(str);
		     str = matcher.replaceAll("");
		     LogHome.getLog().info(str);
		     return str;
	   }
	
	/**
	 * 某些情况下，需获得已拼接完成的sql，可通过此方法获取
	 * @author tiny
	 * @date 2018年4月25日
	 * @param 通过sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest)方法获取到的queryModel
	 * @return 
	 * @Description QueryModel根据QueryModel生成sql语句
	 */
	public static String getSQLByQueryModel(QueryModel queryModel){
		ParseSQLParam parser = getParseSqlParam(queryModel.getSql(), queryModel.getQueryParams());
		return toSqlString(parser.getParseSql(), parser.getValues().toArray());
	}
	
	public static boolean filterType(String fileExt) {
		String allowTypes = "xls,xlsx";
		if ((allowTypes == null) || (allowTypes.equals(""))) {
			return true;
		}
		String[] types = allowTypes.split(",");
		for (String type : types) {
			if (fileExt.toLowerCase().endsWith(type.toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	public static boolean isExcel2007(String filePath) {

		return filePath.matches("^.+\\.(?i)(xlsx)$");
	}
	
	public static boolean isExcel2003(String filePath) {

		return filePath.matches("^.+\\.(?i)(xls)$");

	}
	
	public static String getStringCellValue(Cell cell) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
		String strCell = "";
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_STRING:
			strCell = cell.getStringCellValue();
			break;
		case Cell.CELL_TYPE_NUMERIC:
			String formatString = cell.getCellStyle().getDataFormatString();
			//如果原数据是百分数形式,保留百分数形式
			if(formatString.endsWith("%")){
				
				NumberFormat percentFormat = NumberFormat.getPercentInstance();
				int dotIndex = formatString.indexOf(".");
				if(dotIndex==-1) percentFormat.setMaximumFractionDigits(0); //根据format中小数位数决定精度
				else percentFormat.setMaximumFractionDigits(formatString.length()-2-dotIndex);
				strCell = percentFormat.format(cell.getNumericCellValue());
			}else if ("m/d/yy".equals(formatString)){
				//  strCell=cell.getStringCellValue();
				//  int u=cell.getCellStyle().getDataFormat(); 
				  //  Date date = cell.getDateCellValue();  
				 //   strCell = sdf.format(date);  
				    Timestamp ts=new Timestamp(cell.getDateCellValue().getTime());
				    strCell=ts.toString().substring(0,10);
			}else {
				  strCell = String.valueOf(cell.getNumericCellValue());
			}
			break;
		case Cell.CELL_TYPE_BOOLEAN:
			strCell = String.valueOf(cell.getBooleanCellValue());
			break;
		case Cell.CELL_TYPE_BLANK:
			strCell = "";
			break;
		default:
			strCell = "";
			break;
		}

		if (strCell.equals("") || strCell == null) {
			return "";
		}
		return strCell.replace("'","");
	}
	
	/**
	 * 导入Excel
	 * @param in
	 * @param isExcel2003
	 * @param clazz
	 * @param headerOptions
	 * @return
	 */
	public static <T> List<Map<String,Object>> impExcel(InputStream in, boolean isExcel2003, Class<T> clazz,
			String []tableHeaders,String []dataTypes) {

		List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();

		Workbook hwb;
		try {
			hwb = isExcel2003 ? new HSSFWorkbook(in) : new XSSFWorkbook(in);
			Sheet sheet = hwb.getSheetAt(0);
			int totalRow = sheet.getPhysicalNumberOfRows();
			Assert.isTrue(totalRow > 0, "未正确获取到数据，请检查excel数据!");
			/*Row yearAndMonthRow = sheet.getRow(1); // 获取第2行，里面包含年月
			String yearAndMonth=CommonUtil.getStringCellValue(yearAndMonthRow.getCell(0));
			String belongYear=yearAndMonth.substring(yearAndMonth.lastIndexOf("（")+1,yearAndMonth.lastIndexOf("年")).trim();
			String belongMonth=yearAndMonth.substring(yearAndMonth.lastIndexOf("年")+1,yearAndMonth.lastIndexOf("月")).trim();*/
			Row headerRow = sheet.getRow(1); // 获取表头第一行
			//Row headerRow1 = sheet.getRow(4); // 获取表头第二行
			//int cellTotal = headerRow.getPhysicalNumberOfCells(); // 获取列总数
		/*	String[] tableHeaders = new String[cellTotal];
			for (int i = 0; i < headerOptions.length; i++) { // 按顺序依次生成表头对应的字段名数组
				
				Cell headerCell = headerRow.getCell(i);
				//String cellName = CommonUtil.getStringCellValue(headerCell);
				tableHeaders[i] = headerOptions[i];
				if (headerOptions.get(cellName)==null) {
					headerCell = headerRow1.getCell(i);
					cellName = CommonUtil.getStringCellValue(headerCell);
					if (cellName.contains(".")) {
						cellName=cellName.substring(0, cellName.lastIndexOf("."));
					}				
					tableHeaders[i] = headerOptions.get(cellName);					
				}
			}*/
			Row row = null;			
			for (int i = 1; i < totalRow; i++) {				
				row = sheet.getRow(i);
				Map<String, Object> rowMap = new HashMap<String, Object>(); // 转化成类型
				for (int n = 0; n < tableHeaders.length; n++) {
					String rowValue="";
					if (row.getCell(n)!=null) {
						rowValue = ComUtils.getStringCellValue(row.getCell(n));
						//System.out.println("rowValue======"+rowValue);
					    if ("date".equals(dataTypes[n])){   
					    	rowValue="to_date('"+rowValue+"','yyyy-mm-dd')";
			 	 	      }
					}			
					rowMap.put(tableHeaders[n], rowValue);
				}   //日期格式 需要特殊处理 to_date(?,'')
				resultList.add(rowMap); // 转化成对象    
				//resultList.add(ClassHelper.fromMap(clazz, rowMap)); // 转化成对象
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return resultList;
	}
	
	
	
	//压缩文件夹
	public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
	            throws RuntimeException{
		        
		        long start = System.currentTimeMillis();
		        ZipOutputStream zos = null ;
	        try {
	            zos = new ZipOutputStream(out);
	            File sourceFile = new File(srcDir);
	            compress(sourceFile,zos,sourceFile.getName(),KeepDirStructure);
	            long end = System.currentTimeMillis();
	            System.out.println("压缩完成，耗时：" + (end - start) +" ms");
	
	        } catch (Exception e) {
		            throw new RuntimeException("zip error from ZipUtils",e);
		        }finally{
		            if(zos != null){
	                try {
	                    zos.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	    }
	
	//压缩文件
	 private static void compress(File sourceFile, ZipOutputStream zos, String name,
						             boolean KeepDirStructure) throws Exception{

		byte[] buf = new byte[BUFFER_SIZE];
		if (sourceFile.isFile()) {
			// 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
			zos.putNextEntry(new ZipEntry(name));
			// copy文件到zip输出流中
			int len;
			FileInputStream in = new FileInputStream(sourceFile);
			while ((len = in.read(buf)) != -1) {
				zos.write(buf, 0, len);
			}
			// Complete the entry
			zos.closeEntry();
			in.close();
		} else {
			File[] listFiles = sourceFile.listFiles();
			if (listFiles == null || listFiles.length == 0) {

				// 需要保留原来的文件结构时,需要对空文件夹进行处理
				if (KeepDirStructure) {
					// 空文件夹的处理
					zos.putNextEntry(new ZipEntry(name + "/"));
					// 没有文件，不需要文件的copy
					zos.closeEntry();
				}
			} else {

				for (File file : listFiles) {

					// 判断是否需要保留原来的文件结构
					if (KeepDirStructure) {

						// 注意：file.getName()前面需要带上父文件夹的名字加一斜杠,
						// 不然最后压缩包中就不能保留原来的文件结构,即：所有文件都跑到压缩包根目录下了
						compress(file, zos, name + "/" + file.getName(),
								KeepDirStructure);
					} else {
						compress(file, zos, file.getName(), KeepDirStructure);
					}
				}

			}

		}

	}
	 
	 /**
	  * 解压文件到指定目录
	  * @param zipFile
	  * @param descDir
	  * @author  lxh
	  */
	  @SuppressWarnings("rawtypes")
	  public static void unZipFiles(File zipFile,String descDir)throws IOException{
	  //  File pathFile = new File(descDir);
	  // if(!pathFile.exists()){
	   //   pathFile.mkdirs();
	   //}
	  try{
	  ZipFile zip = new ZipFile(zipFile);
	  for(Enumeration entries = zip.entries();entries.hasMoreElements();){
	   ZipEntry entry = (ZipEntry)entries.nextElement();
	   String zipEntryName = entry.getName();
	   InputStream in = zip.getInputStream(entry);
	   String outPath = (descDir+zipEntryName).replaceAll("\\*", "/");;
	   //判断路径是否存在,不存在则创建文件路径
	   File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
	   if(!file.exists()){
	     file.mkdirs();
	   }
	   //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
	   if(new File(outPath).isDirectory()){
	     continue;
	   }
	   //输出文件路径信息
	  // System.out.println(outPath);
	    
	   OutputStream out = new FileOutputStream(outPath);
	   byte[] buf1 = new byte[1024];
	   int len;
	   while((len=in.read(buf1))>0){
	    out.write(buf1,0,len);
	   }
	     in.close();
	     out.close();
	   }
	    zip.close();
	   } catch (Exception e) {
		   e.printStackTrace();
	   }
	  // System.out.println("******************解压完毕********************");
	  }
	  
	  /*
	   * /csv文件内容转成对象
	   * @param BufferedReader bre
	   * @param Class<T>
	   * @author  lxh
	   */
    public static <T> List<T> dataToObject(BufferedReader bre,Class<T> clazz){
			List<T> resultList = new ArrayList<T>();
		   	Map<String, Object> rowMap = null;
		    String  []tableHeaders=null;// headerOptions.split(",");
		    String line = "",everyLine="";
		    String []datas=null;
		   try {
			   int u=0;
			   String values="";
		     while ((line = bre.readLine()) != null)  //读取到的内容给line变量
	         {
		        everyLine = line;
		        rowMap = new HashMap<String, Object>(); // 转化成对象类型
	            everyLine=everyLine.replaceAll("\"", "");
	         // System.out.println(everyLine); 
	             datas=everyLine.split(",");
	            if (u==0){ //表头
	            	everyLine=CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, everyLine);
	            	tableHeaders=everyLine.split(",");
	            }else{
	              for (int i = 0; i < tableHeaders.length; i++) {
	               	  if (i<datas.length) {
	               		  values=datas[i].replace("~$~", ",");//因为包含逗号 都转成了~$~。此时再转回来
	               		  rowMap.put(tableHeaders[i],values);
	               		  //由于模板的node_type映射字段是parentNodeType 需要特殊处理一下
	               		  if  ("com.pm.template.domain.model.ProjectTemplate".equals(clazz.getTypeName())){
	               			if ("nodeType".equals(tableHeaders[i])){
	               				rowMap.put("parentNodeType",values);
	               			}
	               		  }
		               	  if ("id".equals(tableHeaders[i])){
		               		 rowMap.put("oldId", values);
		               	  }

	            	  } else {
	            		  rowMap.put(tableHeaders[i],"");
	            	  }
			      }
	      	         resultList.add(ClassHelper.fromMap(clazz, rowMap)); // 转化成对象
	            }
	    	    u++;
	    	   // System.out.println("csv表格中所有行数："+u);
	         }
		  } catch (IOException e) {
			try {
				bre.close();
			} catch (IOException e1) {
					e1.printStackTrace();
			}
			e.printStackTrace();
			
		   } finally{
			 try {
				bre.close();
			 } catch (IOException e) {
				e.printStackTrace();
			 }
		  }
			return resultList;
		}
			
    // 正确的IP拿法，即优先拿site-local地址
    public static InetAddress getLocalHostLANAddress() throws UnknownHostException {
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration<?> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration<?> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址，就是它了
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            if (jdkSuppliedAddress == null) {
                throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
            }
            return jdkSuppliedAddress;
        } catch (Exception e) {
            UnknownHostException unknownHostException = new UnknownHostException(
                    "Failed to determine LAN address: " + e);
            unknownHostException.initCause(e);
            throw unknownHostException;
        }
    }
    
    /**
     * 获取系统年份
     */
	public static Integer getSysYear() {
		Calendar date = Calendar.getInstance();
		String year = String.valueOf(date.get(Calendar.YEAR));
		return Integer.parseInt(year);
	}
	
	/**
	 * 根据行生成map,key自动生成为col_001的格式
	 * @author tiny
	 * @date 2019年2月13日
	 * @param row excel 行
	 * @param isHeader 是否为表头
	 * @return
	 * @Description 根据行生成map
	 */
	public static Map<String,Object> getMapByExcelRow(Row row,boolean... isHeader){
		int cellTotal = row.getPhysicalNumberOfCells(); // 获取列总数
		
		Map<String,Object> result = new HashMap<String,Object>();
		for(int i = 0;i<cellTotal;i++){
			Cell cell = row.getCell(i);
			String value = ComUtils.getStringCellValue(cell);
			if(isHeader.length==0||!isHeader[0]){ //如果是普通行
				if(StringUtil.isNotBlank(value)&&StringUtil.isNumber(value)){
					value=value.replaceAll("0+$", "").replaceAll("[.]$", "");
				}
				result.put("col"+String.format("%03d", i),value);
			}else{//如果是表头
				if(StringUtil.isNotBlank(value)){
					result.put("col"+String.format("%03d", i),value);
				}
			}
			
		}
		return result;
	}
	
	/**
	 * 
	 * @author tiny
	 * @date 2019年2月13日
	 * @param sheet
	 * @param isExcel2003
	 * @return
	 * @Description 分析表头
	 */
	public static Map<String,Object> getExcelTableHeader(Sheet sheet){
		int totalRow = sheet.getPhysicalNumberOfRows();
		Assert.isTrue(totalRow > 0, "未正确获取到数据，请检查excel数据!");
		Row headerRow = sheet.getRow(0); // 获取第2行，里面包含年月
		return ComUtils.getMapByExcelRow(headerRow,true);
	}
	
	/**
	 * 获取excel数据，封装成平台grid的后台数据格式（无分页）
	 * @author tiny
	 * @date 2019年2月13日
	 * @param sheet excel工作表 
	 * @return
	 * @Description 获取excel数据
	 */
	public static Map<String,Object> getExcelDatas(Sheet sheet,Map<String,Object>... baseMaps){
		int totalRow = sheet.getPhysicalNumberOfRows();
		Assert.isTrue(totalRow > 0, "未正确获取到数据，请检查excel数据!");
		Map<String,Object> result = new HashMap<String,Object>();
		List<Map<String,Object>> rows = new ArrayList<Map<String,Object>>();
		for(int i = 1;i<totalRow;i++){ //从第二行开始为数据
			Row row = sheet.getRow(i);
			Map<String,Object> rowMap = ComUtils.getMapByExcelRow(row);
			for(Map<String,Object> baseMap :baseMaps){
				Map<String,Object> _baseMap = new HashMap();
				_baseMap.putAll(baseMap);
				_baseMap.putAll(rowMap);
				rowMap = _baseMap;
			}
			rows.add(rowMap);
		}
		result.put("Rows", rows);
		result.put("Total", rows.size());
		return result;
	}
	
	/**
	 * 生成多行插入语句
	 * @author tiny
	 * @date 2019年2月14日
	 * @param tableName 表名 
	 * @param datas 数据列表
	 * @param colums 字段列表
	 * @return
	 * @Description 生成多行插入语句
	 */
	public static String getMultiInsertSqlByList(String tableName,Map<String,Object> map,String columns){
		String itStr = String.format(" into %s(%s) values (%s)", tableName,columns,"%s");
		StringBuffer intoSql = new StringBuffer();
		String[] columnNames = columns.split(",");
		String sql ="";
		try {
			//for(Map<String,Object> map : datas){
			StringBuffer valuesSql = new StringBuffer();

			for (String key : columnNames) {
				//	String realKey = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, key);
				//String realKey = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key).toUpperCase();
				String value = MapUtils.getString(map, key, "");
				if (key.equalsIgnoreCase("id")) {
					if (map.get("id") != null && !"" .equals(map.get("id").toString())) {
						valuesSql.append(String.format(",'%s'", value));
					} else {
						valuesSql.append(",sys_guid()");
					}
				} else if (key.equalsIgnoreCase("created_date") || key.equalsIgnoreCase("fillin_date")) {
					valuesSql.append(",sysdate");
				} else if (value.startsWith("to_date(")) { //日期格式值  去掉单引号
					valuesSql.append(String.format(",%s", value));
				} else {
					value = value.replace("'", "''");
					valuesSql.append(String.format(",'%s'", value));
				}
			}
			intoSql.append(String.format(itStr, valuesSql.substring(1)));
			//}
			 sql = String.format("insert all %s select * from dual", intoSql.toString());
		}catch (Exception ex){
			ex.printStackTrace();
		}
		return sql.toString();
	}
	
	/**
	 * 根据columns拼接需要update的字段 
	 * @author tiny
	 * @date 2019年2月14日
	 * @param columns
	 * @return
	 * @Description TODO(这里用一句话描述这个方法的作用)
	 */
	public static String getMultiUpdateColumnSqlByList(List <Map<String, Object>> fieldList,String columns){
		String[] _columns = columns.split(",");
		for(int i =0;i<_columns.length;i++){
			if(fieldList!=null&&!"id".equals(_columns[i])){
				for (Map<String, Object> map : fieldList) {
					if(map.get("fieldCode").equals(_columns[i])){
						if  ("date".equals((map.get("fieldType").toString()))){
							_columns[i] = String.format("%s =to_date(?,'yyyy-mm-dd hh24:mi:ss')", _columns[i]);
						} else {
							_columns[i] = String.format("%s = ?", _columns[i]);
						}
						break;
					}
				}
			}
			if("is_audit".equals(_columns[i])){
				_columns[i] = String.format("%s = ?", _columns[i]);
			}
		}
		return String.join(",", _columns);
	}
	
	public static String getMultiUpdateColumnSqlByReceiveData(List <Map<String, Object>> fieldList,String columns){
		String[] _columns = columns.split(",");
		for(int i =0;i<_columns.length;i++){
			if(fieldList!=null&&!"id".equals(_columns[i])){
				//for (Map<String, Object> map : fieldList) {
					//if(map.get("fieldCode").equals(_columns[i])){
						/*if  ("date".equals((map.get("fieldType").toString()))){
							_columns[i] = String.format("%s =to_date(?,'yyyy-mm-dd')", _columns[i]);
						} else {*/
							_columns[i] = String.format("%s = ?", _columns[i]);
						//}
					//	break;
					//}
				//}
			}
			if("is_audit".equals(_columns[i])){
				_columns[i] = String.format("%s = ?", _columns[i]);
			}
		}
		return String.join(",", _columns);
	}

	/**
	 * 将List<Map<String,Object>>形式的参数转化为List<Object[]>的形式
	 * @author tiny
	 * @date 2019年2月14日
	 * @param datas 需要转化的参数
	 * @param columns column中必须包含id
	 * @return
	 * @Description 将List<Map<String,Object>>形式的参数转化为List<Object[]>的形式
	 */
	public static List<Object[]> convertListMapToListObjects(List<Map<String,Object>> datas,String columns){
		List<String> _columns = Arrays.asList(columns.split(","));
		Assert.isTrue(StringUtil.isNotBlank(columns) && _columns.contains("id"), "columns中必须包含id字段");
		List<Object[]> result = new ArrayList<Object[]>();
		int size = _columns.size();
		for(Map<String,Object> map : datas){
			Object[] objs = new Object[size]; 
			if(!StringUtil.isBlank(MapUtils.getString(map,"id"))){ //查找id不为空的对象进行update
				for(int i = 0,idx=0;i<size;i++){
					if(!"id".equalsIgnoreCase(_columns.get(i))){
						objs[idx] = MapUtils.getString(map,_columns.get(i),"");
						idx++;
					}
				}
				objs[size-1] = MapUtils.getString(map,"id"); //将id参数放入最后一位
			}
			result.add(objs);
		}
		return result;
	}
	
	/**
	 * 根据类型迭代查询出对应的字段，避免提交到前端的字段查过实际可能需要查询的数量
	 * @author tiny
	 * @date 2019年2月20日
	 * @param cls
	 * @return
	 * @Description 根据类型迭代查询出实体类中存在的字段
	 */
	public static List<String> getColumnnamesByClass(Class<?> cls,String... otherColumns) {
		ArrayList<String> names = new ArrayList<String>();
		Field[] fields = cls.getDeclaredFields();
		if(!cls.getSuperclass().getSimpleName().equals("Object")) names.addAll(getColumnnamesByClass(cls.getSuperclass()));
		for(Field field :fields){
			if(Modifier.isFinal(field.getModifiers())) continue;
			if(field.isAnnotationPresent(Transient.class)) continue;
			if(field.isAnnotationPresent(Embedded.class)) {
				names.addAll(getColumnnamesByClass(field.getType()));
			}else{
				Column cm = field.getAnnotation(Column.class);
				if(cm==null){
					names.add(field.getName().toUpperCase());
				}else{
					names.add(cm.name().toUpperCase());
				}
			}
		}
		if(otherColumns!=null && otherColumns.length>0){
			for(String columnName : otherColumns){
				names.add(columnName.toUpperCase());
			}
			//names.addAll(Arrays.asList(otherColumns));
		}
		return names;
	}
	
	public static String createExcelXml(Map<String,Object>... maps) {
		StringBuffer excelHead=new StringBuffer("<tables><table>");
		
		if(maps.length>0&&maps[0]!=null&&!maps[0].isEmpty()){ //1个参数
			List<String> columnCodeList = new ArrayList<String>();
			excelHead.append("<row>");
			List<Map<String,Object>> headers = (List<Map<String,Object>>)maps[0].get("Rows");
			String baseAttribute = "";
			if(maps.length>1&&maps[1]!=null&&!maps[1].isEmpty()){
				StringBuffer strBuffer = new StringBuffer();
				Map<String,Object> baseData = maps[1];
				for(Entry<String,Object> entry :baseData.entrySet()){
					strBuffer.append(String.format("%s='%s' ",entry.getKey(),entry.getValue()));
				}
				baseAttribute = strBuffer.toString();
			}
			
			for(Map<String,Object> headerColumn : headers){
				String columnName = MapUtils.getString(headerColumn, "columnCode");
				columnName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, columnName);
				columnCodeList.add(columnName);
				
				excelHead.append(String.format("<col %s>%s</col>", baseAttribute,MapUtils.getString(headerColumn, "columnName")));
			}
			excelHead.append("</row>");
			
			if(maps.length>2&&maps[2]!=null&&!maps[2].isEmpty()&&(Integer)maps[2].get("Total")>0){ //3个参数
				List<Map<String,Object>> datas = (List<Map<String,Object>>)maps[2].get("Rows");
				for(Map<String,Object> row : datas){
					excelHead.append("<row>");
					for(String columnName :columnCodeList){
						excelHead.append(String.format("<col>%s</col>", MapUtils.getString(row, columnName)));
					}
					excelHead.append("</row>");
				}
			}
		}
//		excelHead.append(dealdata(str));
		excelHead.append("</table></tables>");
		return excelHead.toString();
	}
	
    // 文件复制
    public static void copyFile(File fromFile,File toFile) throws IOException{
        FileInputStream ins = new FileInputStream(fromFile);
        FileOutputStream out = new FileOutputStream(toFile);
        byte[] b = new byte[1024];
        int n=0;
        while((n=ins.read(b))!=-1){
            out.write(b, 0, n);
        }
        
        ins.close();
        out.close();
    }
    //删除文件夹
    public static void delFolder(String folderPath) {  
        try {  
           delAllFile(folderPath); //删除完里面所有内容  
           String filePath = folderPath;  
           filePath = filePath.toString();  
           java.io.File myFilePath = new java.io.File(filePath);  
            myFilePath.delete(); //删除空文件夹  
        } catch (Exception e) {  
          e.printStackTrace();   
        }  
   }  
    
   //删除指定文件夹下的所有文件
	public static boolean delAllFile(String path) {
		boolean flag = false;
		File file = new File(path);
		if (!file.exists()) {
			return flag;
		}
		if (!file.isDirectory()) {
			return flag;
		}
		String[] tempList = file.list();
		File temp = null;
		for (int i = 0; i < tempList.length; i++) {
			if (path.endsWith(File.separator)) {
				temp = new File(path + tempList[i]);
			} else {
				temp = new File(path + File.separator + tempList[i]);
			}
			if (temp.isFile()) {
				temp.delete();
			}
			if (temp.isDirectory()) {
				delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
				delFolder(path + "/" + tempList[i]);// 再删除空文件夹
				flag = true;
			}
		}
		return flag;
	}
	
	//一个根据Map中指定key对List<Map>进行排序的公用内部类
	public static class CommonMapComparator implements Comparator<Map<String,Object>>{
		private String compareKey = "";
		private int compareType = 0;
		public static int INT_TYPE = 0;
		
		public CommonMapComparator(){};
		public CommonMapComparator(String compareKey){this.setCompareKey(compareKey);};
		public CommonMapComparator(String compareKey,int compareType){
			this.setCompareKey(compareKey);
			this.setCompareType(compareType);
		};
		
		public static CommonMapComparator getInstance(String compareKey,int compareType){
			return new CommonMapComparator(compareKey,compareType);
		}
		
		public static CommonMapComparator getInstance(String compareKey){
			return new CommonMapComparator(compareKey);
		}
		
		@Override
		public int compare(Map<String,Object> pre, Map<String,Object> next) { //比较
			if(this.getCompareType() == CommonMapComparator.INT_TYPE){
				int preLv = MapUtils.getIntValue(pre, this.getCompareKey(), 0);
				int nextLv = MapUtils.getIntValue(next, this.getCompareKey(), 0);
				return preLv - nextLv;
			}else{
				return MapUtils.getString(pre, this.getCompareKey(), "").compareTo(MapUtils.getString(next, this.getCompareKey(), ""));
			}
		}
		public String getCompareKey() {
			return compareKey;
		}
		public void setCompareKey(String compareKey) {
			this.compareKey = compareKey;
		}
		public int getCompareType() {
			return compareType;
		}
		public void setCompareType(int compareType) {
			this.compareType = compareType;
		}
	}

	 /***
	   * 获取下一个英文字母
	   * @param en
	   * @return
	   */
	 public static String getNextUpEn(String en){

			if(en==null || en.equals(""))
				return "A";
		    char lastE = 'Z';
		    int lastEnglish = (int)lastE;
		    char[] c = en.toCharArray();
		    if(c.length>1){
		    	return null;
		    }else{
		    	int now = (int)c[0];
		    	if(now >= lastEnglish)
		    		return null;
		    	char uppercase = (char)(now+1);
		    	return String.valueOf(uppercase);
		    }
	}
	 
	
}
