package com.ukefu.util.task;

import static org.elasticsearch.index.query.QueryBuilders.termQuery;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
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.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.data.domain.PageImpl;

import com.google.common.collect.ArrayListMultimap;
import com.ukefu.core.UKDataContext;
import com.ukefu.util.UKTools;
import com.ukefu.util.es.SearchTools;
import com.ukefu.util.es.UKDataBean;
import com.ukefu.util.extra.DataExchangeInterface;
import com.ukefu.webim.service.repository.JobDetailRepository;
import com.ukefu.webim.service.repository.ReporterRepository;
import com.ukefu.webim.web.model.JobDetail;
import com.ukefu.webim.web.model.MetadataTable;
import com.ukefu.webim.web.model.SysDic;
import com.ukefu.webim.web.model.TableProperties;
import com.ukefu.webim.web.model.UKeFuDic;

public class ExcelImportProecess extends DataProcess{
	private DecimalFormat format = new DecimalFormat("###");
	private AtomicInteger pages = new AtomicInteger() , errors = new AtomicInteger(); 
	
	public ExcelImportProecess(DSDataEvent event){
		super(event);
	}
	
	@Override
	public void process() {
		processExcel(event);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void processExcel(final DSDataEvent event){
		InputStream is = null;  
    	try {
    		event.getDSData().getReport().setTableid(event.getDSData().getTask().getId());
    		if(event.getDSData().getUser()!=null){
    			event.getDSData().getReport().setUserid(event.getDSData().getUser().getId());
    			event.getDSData().getReport().setUsername(event.getDSData().getUser().getUsername());
    		}
    		
            try {  
                is = new FileInputStream(event.getDSData().getFile());  
            } catch (FileNotFoundException ex) {  
                ex.printStackTrace();
            }  
            boolean isExcel2003 = true;  
            if (isExcel2007(event.getDSData().getFile().getName())) {  
                isExcel2003 = false;  
            }
            
            Workbook wb = null;  
            try {  
                wb = isExcel2003 ? new HSSFWorkbook(is) : new XSSFWorkbook(is);  
            } catch (IOException ex) {  
                ex.printStackTrace();
            }  
            long start = System.currentTimeMillis() ;
            if(wb!=null) {
	            Sheet sheet = wb.getSheetAt(0);  
	            Row titleRow = sheet.getRow(0);
	            Row valueRow = sheet.getRow(1);
	            int totalRows = sheet.getPhysicalNumberOfRows(); 
	            int colNum = titleRow.getPhysicalNumberOfCells();
	            for(int i=2 ; i<totalRows && valueRow == null ; i++){
	            	valueRow = sheet.getRow(i);
	            	if(valueRow !=null){
	            		break ;
	            	}
	            }
	            /**
	             * 需要检查Mapping 是否存在
	             */
	            
	            Map<Object, List> refValues = new HashMap<Object , List>() ;
	            MetadataTable table = event.getDSData().getTask() ;
	            for(TableProperties tp : table.getTableproperty()){
	            	if(tp.isReffk() && !StringUtils.isBlank(tp.getReftbid())){
	            		DataExchangeInterface exchange = (DataExchangeInterface) UKDataContext.getContext().getBean(tp.getReftbid()) ;
	            		refValues.put(tp.getFieldname(), exchange.getListDataByIdAndOrgi(null, null, event.getOrgi())) ;
	            	}
	            }
	            
	            for(int i=1 ; i<totalRows; i++){
	            	Row row = sheet.getRow(i) ;
	            	Object data = null ;
	            	if(row!=null && !isRowEmpty(row)){
						if(event.getDSData().getClazz() != null) {
							data = event.getDSData().getClazz().newInstance() ;
						}
						Map<Object, Object> values = new HashMap<Object , Object>() ;
						ArrayListMultimap<String, Object> multiValues = ArrayListMultimap.create();
						boolean skipDataVal = false; //跳过数据校验
						StringBuffer pkStr = new StringBuffer() , allStr = new StringBuffer();
						for(int col=0 ; col<colNum ; col++){
							Cell value = row.getCell(col) ;
							Cell title = titleRow.getCell(col) ;
							String titleValue = getValue(title) ;
							if(!StringUtils.isBlank(titleValue)) {
								titleValue = titleValue.trim() ;
							}
							TableProperties tableProperties = getTableProperties(event, titleValue);
							if(tableProperties!=null && value!=null){
								String valuestr = getValue(value) ;
								if(!StringUtils.isBlank(valuestr)) {
									if(tableProperties.isModits()){
										if(!StringUtils.isBlank(valuestr)) {
											multiValues.put(tableProperties.getFieldname(), valuestr) ;
										}
									}else{
										if(tableProperties.isSeldata()){
											SysDic sysDic = UKeFuDic.getInstance().getDicItem(valuestr) ;
											if(sysDic!=null){
												values.put(tableProperties.getFieldname(), sysDic.getName()) ;
											}else{
												List<SysDic> dicItemList = UKeFuDic.getInstance().getSysDic(tableProperties.getSeldatacode());
												if(dicItemList!=null && dicItemList.size() > 0) {
													for(SysDic dicItem : dicItemList) {
														if(dicItem.getName().equals(valuestr)) {
															values.put(tableProperties.getFieldname(), dicItem.isDiscode()?dicItem.getCode():dicItem.getId()) ; break ;
														}
													}
												}
											}
										}else if(tableProperties.isReffk() && refValues.get(tableProperties.getFieldname())!=null){
											List keys = refValues.get(tableProperties.getFieldname()) ;
											if(keys != null) {
												values.put(tableProperties.getFieldname() , getRefid(tableProperties,refValues.get(tableProperties.getFieldname()) , valuestr)) ;
											}
										}else{
											values.put(tableProperties.getFieldname(), valuestr) ;
										}
										if(tableProperties.isPk() && !tableProperties.getFieldname().equalsIgnoreCase("id")){
											pkStr.append(valuestr) ;
										}
									}
									allStr.append(valuestr) ;
								}
								event.getDSData().getReport().setBytes(event.getDSData().getReport().getBytes() + valuestr.length());
								event.getDSData().getReport().getAtompages().incrementAndGet() ;
							}
						}
						values.put("orgi", event.getOrgi()) ;
						if(values.get("id") == null){
							if(pkStr.length() > 0) {
								values.put("id", UKTools.md5(pkStr.append(event.getDSData().getTask().getTablename()).toString())) ;
							}else {
								values.put("id", UKTools.md5(allStr.append(event.getDSData().getTask().getTablename()).toString())) ;
							}
						}
						if(event.getValues()!=null && event.getValues().size() > 0){
							values.putAll(event.getValues());
						}
						values.putAll(multiValues.asMap());
						String validFaildMessage = null ;
						for(TableProperties tp : table.getTableproperty()){
							if(!StringUtils.isBlank(tp.getDefaultvaluetitle())) {
								String valuestr = (String) values.get(tp.getFieldname()) ;
								if(tp.getDefaultvaluetitle().indexOf("required") >= 0 && StringUtils.isBlank(valuestr)) {
									skipDataVal = true ; validFaildMessage = "required" ;break ;
								}else if(valuestr!=null && (tp.getDefaultvaluetitle().indexOf("numstr") >= 0 && !valuestr.matches("[\\d]{1,}"))) {
									skipDataVal = true ; validFaildMessage = "numstr" ;break ;
								}else if(valuestr!=null && (tp.getDefaultvaluetitle().indexOf("datenum") >= 0 || tp.getDefaultvaluetitle().indexOf("datetime") >= 0 )) {
									if(!valuestr.matches("[\\d]{4,4}-[\\d]{2,2}-[\\d]{2,2}") && !valuestr.matches("[\\d]{4,4}-[\\d]{2,2}-[\\d]{2} [\\d]{2,2}:[\\d]{2,2}:[\\d]{2,2}")) {
										skipDataVal = true ; validFaildMessage = "datenum" ; break ;
									}else {
										if(valuestr.matches("[\\d]{4,4}-[\\d]{2,2}-{1,1}")) {
											if("date".equals(tp.getDefaultfieldvalue())) {
												values.put(tp.getFieldname(),UKTools.simpleDateFormat.parse(valuestr));
											}else {
												values.put(tp.getFieldname(),UKTools.simpleDateFormat.format(UKTools.simpleDateFormat.parse(valuestr)));
											}
										}else if(valuestr.matches("[\\d]{4,4}-[\\d]{2,2}-[\\d]{2,2} [\\d]{2,2}:[\\d]{2,2}:[\\d]{2,2}")) {
											if("date".equals(tp.getDefaultfieldvalue())) {
												values.put(tp.getFieldname(),UKTools.dateFormate.parse(valuestr));
											}else {
												values.put(tp.getFieldname(),UKTools.simpleDateFormat.format(UKTools.dateFormate.parse(valuestr)));
											}
											
										}
									}
								}
							}
			            	if(tp.isReffk() && !StringUtils.isBlank(tp.getReftbid()) && refValues.get(tp.getFieldname()) == null){
			            		DataExchangeInterface exchange = (DataExchangeInterface) UKDataContext.getContext().getBean(tp.getReftbid()) ;
			            		exchange.process(data, event.getOrgi());
			            	}
			            }
						
						if(!values.containsKey("orgi")) {
							skipDataVal = true ;
						}
						event.getDSData().getReport().setTotal(pages.intValue());
						values.put("creater", event.getValues().get("creater")) ;
						if(data!=null && skipDataVal == false) {
							UKTools.populate(data, values);
							pages.incrementAndGet() ;
							event.getDSData().getProcess().process(data);
						}else if(data == null){
							/**
							 * 导入的数据,只写入ES
							 */
							if(skipDataVal == true) {	//跳过
								values.put("status", "invalid") ;
								values.put("validresult", "invalid") ;
								values.put("validmessage", validFaildMessage!=null ? validFaildMessage : "") ;
							}else {
								values.put("validresult", "valid") ;
							}
							values.put("status", UKDataContext.NamesDisStatusType.NOT.toString()) ;
							values.put("batid", event.getBatid()) ;
							
							values.put("createtime", System.currentTimeMillis()) ;
							values.put("callstatus", UKDataContext.NameStatusTypeEnum.NOTCALL.toString()) ;
							values.put("execid", event.getDSData().getReport().getId()) ;
							
							if(i%500 == 0) {
								UKDataContext.getContext().getBean(ReporterRepository.class).save(event.getDSData().getReport()) ;
							}
							
							if(values.get("cusid")==null) {
								/**
								 * 
								 */
								values.put("cusid", values.get("id"))  ;
							}
							pages.incrementAndGet() ;
							event.getDSData().getProcess().process(values);
							
							/**
							 * 访客信息表
							 */
						}
						if(skipDataVal == true) {	//跳过
							errors.incrementAndGet();
							continue ;
						}
	            	}
				}
            }
            
            event.setTimes(System.currentTimeMillis() - start);
            event.getDSData().getReport().setEndtime(new Date());
            event.getDSData().getReport().setAmount(String.valueOf((float)event.getTimes()/1000f));
            event.getDSData().getReport().setStatus(UKDataContext.TaskStatusType.END.getType());
            event.getDSData().getReport().setTotal(pages.intValue());
            event.getDSData().getReport().setPages(pages.intValue());
            event.getDSData().getReport().setErrors(errors.intValue());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(is!=null){
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(event.getDSData().getFile().exists()){
				event.getDSData().getFile().delete() ;
			}
			event.getDSData().getProcess().end();
			/**
			 * 更新数据
			 */
			UKDataContext.getContext().getBean(ReporterRepository.class).save(event.getDSData().getReport()) ;
			if(event.getDSData().getClazz() == null && !StringUtils.isBlank(event.getBatid())) {
				JobDetailRepository batchRes = UKDataContext.getContext().getBean(JobDetailRepository.class) ;
				JobDetail batch = this.event.getDSData().getJobDetail();
				if(batch == null) {
					batch = batchRes.findByIdAndOrgi(event.getBatid(), event.getOrgi()) ;
				}
				if(batch!=null) {
					
					BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
					queryBuilder.must(termQuery("orgi",batch.getOrgi()));
					queryBuilder.must(termQuery("batid",batch.getId()));
					PageImpl<UKDataBean> aggregationBatchData = SearchTools.aggregationBatchData(queryBuilder, true, 0, 1, "batid");
					if(aggregationBatchData != null && aggregationBatchData.getContent().size() > 0) {
						UKDataBean uKDataBean = aggregationBatchData.getContent().get(0);
						//总数
						if(uKDataBean.getValues().get("total") != null) {
							batch.setNamenum(Integer.parseInt(uKDataBean.getValues().get("total").toString()));
						}else {
							batch.setNamenum(0);
						}
						//未分配
						if(uKDataBean.getValues().get("status.not") != null){
							batch.setNotassigned(Integer.parseInt(uKDataBean.getValues().get("status.not").toString()));
							//已分配
							batch.setAssigned(batch.getNamenum() - Integer.parseInt(uKDataBean.getValues().get("status.not").toString()));
						}else {
							batch.setNotassigned(0);
							//已分配
							batch.setAssigned(batch.getNamenum());
						}
						//有效
						if(uKDataBean.getValues().get("validresult.valid") != null) {
							batch.setValidnum(Integer.parseInt(uKDataBean.getValues().get("validresult.valid").toString()));
						}else {
							batch.setValidnum(0);
						}
						//无效
						if(uKDataBean.getValues().get("validresult.invalid") != null) {
							batch.setInvalidnum(Integer.parseInt(uKDataBean.getValues().get("validresult.invalid").toString()));
						}else {
							batch.setInvalidnum(0);
						}
						
					}
					batchRes.save(batch) ;
				}
			}
		}
	}
	
	private String getRefid(TableProperties tp , List<Object> dataList , String value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
		String id = "" ;
		for(Object data : dataList){
			Object target = null ;
			if(PropertyUtils.isReadable(data, "name")){
				target = BeanUtils.getProperty(data, "name") ;
				if(target!=null && target.equals(value)){
					id = BeanUtils.getProperty(data, "id") ;
				}
			}
			if(PropertyUtils.isReadable(data, "tag")){
				target = BeanUtils.getProperty(data, "tag") ;
				if(target!=null && target.equals(value)){
					id = BeanUtils.getProperty(data, "id") ;
				}
			}
			if(StringUtils.isBlank(id) && PropertyUtils.isReadable(data, "title")){
				target = BeanUtils.getProperty(data, "title") ; 
				if(target!=null && target.equals(value)){
					id = BeanUtils.getProperty(data, "id") ;
				}
			}
			if(StringUtils.isBlank(id)){
				target = BeanUtils.getProperty(data, "id") ; 
				if(target!=null && target.equals(value)){
					id = target.toString() ;
				}
			}
		}
		return id ;
	}
	
	private TableProperties getTableProperties(DSDataEvent event , String title){
		TableProperties tableProperties = null ; 
		for(TableProperties tp : event.getDSData().getTask().getTableproperty()){
			if(tp.getName().equals(title) || tp.getFieldname().equals(title)){
				tableProperties = tp ; break ;
			}
		}
		return tableProperties;
	}
	
	//判断空行
	@SuppressWarnings("deprecation")
	private static boolean isRowEmpty(Row row) {
		for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
			Cell cell = row.getCell(c);
			if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK)
				return false;
		}
		return true;
	}
	private boolean isExcel2007(String fileName) {  
        return fileName.matches("^.+\\.(?i)(xlsx)$");  
    } 
	@SuppressWarnings("deprecation")
	private String getValue(Cell cell){
		String strCell = "";
		if(cell!=null){
			short dt = cell.getCellStyle().getDataFormat() ;
	        switch (cell.getCellType()) {
		        case HSSFCell.CELL_TYPE_STRING:
		            strCell = cell.getStringCellValue();
		            break;
		        case HSSFCell.CELL_TYPE_BOOLEAN:
		            strCell = String.valueOf(cell.getBooleanCellValue());
		            break;
		        case HSSFCell.CELL_TYPE_BLANK:
		            strCell = "";
		            break;
		        case HSSFCell.CELL_TYPE_NUMERIC:
		        	if (HSSFDateUtil.isCellDateFormatted(cell)) {
		        		SimpleDateFormat sdf = null;  
		                if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {  
		                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
		                } else {// 日期  
		                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
		                }  
		                strCell = sdf.format(cell.getDateCellValue());  
		        	} else if (cell.getCellStyle().getDataFormat() == 58) {  
		                // 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)  
		                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
		                double value = cell.getNumericCellValue();  
		                strCell = sdf.format(org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value));  
		            }else{
		            	
		            	if (HSSFDateUtil.isCellDateFormatted(cell)) {
		            		SimpleDateFormat sdf = null;  
			                if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {  
			                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
			                } else {// 日期  
			                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
			                }  
			                strCell = sdf.format(cell.getDateCellValue());  
			        	}else{
			            	boolean isNumber = isNumberFormat(dt) ;
			        		if(isNumber){
			        			DecimalFormat numberFormat = getNumberFormat(cell.getCellStyle().getDataFormatString()) ;
			        			if(numberFormat!=null){
			        				strCell = String.valueOf(numberFormat.format(cell.getNumericCellValue()));
			        			}else{
			        				strCell = String.valueOf(cell.getNumericCellValue());
			        			}
			        		}else{
			        			strCell = String.valueOf(format.format(cell.getNumericCellValue())) ;
			        		}
			        	}
	                }
		            break;
		        case HSSFCell.CELL_TYPE_FORMULA: {
	                // 判断当前的cell是否为Date
		        	boolean isNumber = isNumberFormat(dt) ;
		        	try{
		        		if(isNumber){
		        			strCell = String.valueOf(cell.getNumericCellValue());
			        	}else{
			        		strCell = "";
			        	}
		        	}catch(Exception ex){
		        		ex.printStackTrace();
		        		strCell = cell.getRichStringCellValue().getString();  
		        	}
	                break;
	            }
		        default:
		            strCell = "";
		            break;
	        }
	        if (strCell.equals("") || strCell == null) {
	            return "";
	        }
		}
        return strCell;
	}
	
	@SuppressWarnings({ "deprecation", "unused" })
	private String getDataType(Cell cell){
		String dataType = "string";
		if(cell!=null){
			short dt = cell.getCellStyle().getDataFormat() ;
	        switch (cell.getCellType()) {
		        case HSSFCell.CELL_TYPE_STRING:
		        	dataType = "string";
		            break;
		        case HSSFCell.CELL_TYPE_BOOLEAN:
		        	dataType = "number";
		            break;
		        case HSSFCell.CELL_TYPE_BLANK:
		        	if (HSSFDateUtil.isCellDateFormatted(cell)) {
		        		if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {  
		        			dataType = "datetime" ;  
		                } else {// 日期  
		                	dataType = "datetime" ;  
		                }  
		        		
		        	} else if (cell.getCellStyle().getDataFormat() == 58){
		        		dataType = "datetime" ;
		        	}else{
		        		boolean isNumber = isNumberFormat(dt) ;
		        		if(isNumber){
		        			dataType = "number";
		        		}else{
		        			dataType = "string";
		        		}
		        	}
		            break;
		        case HSSFCell.CELL_TYPE_NUMERIC:
		        	if (HSSFDateUtil.isCellDateFormatted(cell)) {
		        		if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {  
		        			dataType = "datetime" ;  
		                } else {// 日期  
		                	dataType = "datetime" ;  
		                }  
		        		
		        	} else if (cell.getCellStyle().getDataFormat() == 58){
		        		dataType = "datetime" ;
		        	}else{
		        		if (HSSFDateUtil.isCellDateFormatted(cell)) {
			        		if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {  
			        			dataType = "datetime" ;  
			                } else {// 日期  
			                	dataType = "datetime" ;  
			                }  
			        	}else{
			        		boolean isNumber = isNumberFormat(dt) ;
			        		if(isNumber){
			        			dataType = "number";
			        		}else{
			        			dataType = "string";
			        		}
			        	}
	                }
		            break;
		        case HSSFCell.CELL_TYPE_FORMULA: {
	                // 判断当前的cell是否为Date
		        	boolean isNumber = isNumberFormat(dt) ;
	        		if(isNumber){
	        			dataType = "number";
	        		}else{
	        			dataType = "string";
	        		}
	                break;
	            }
		        default:
		        	dataType = "string";
		            break;
	        }
	       
		}
        return dataType;
	}
	
	private DecimalFormat getNumberFormat(String dataformat){
		DecimalFormat numberFormat = null ;
		int index = dataformat.indexOf("_") > 0 ?  dataformat.indexOf("_") : dataformat.indexOf(";") ;
		if(index > 0){
			String format = dataformat.substring( 0 , index) ;
			if(format.matches("[\\d.]{1,}")){
				numberFormat = new DecimalFormat(format);
			}
		}
		
		return numberFormat ;
	}
	
	private boolean isNumberFormat(short dataType){
		boolean number = false ;
		switch(dataType){
			case 180 : number = true  ; break; 
			case 181 : number = true  ; break; 
			case 182 : number = true  ; break;
			case 178 : number = true  ; break;
			case 177 : number = true  ; break;
			case 176 : number = true  ; break;
			case 183 : number = true  ; break; 
			case 185 : number = true  ; break; 
			case 186 : number = true  ; break;
			case 179 : number = true  ; break;
			case 187 : number = true  ; break; 
			case 7 : number = true  ; break; 
			case 8 : number = true  ; break; 
			case 44 : number = true  ; break; 
			case 10 : number = true  ; break; 
			case 12 : number = true  ; break; 
			case 13 : number = true  ; break; 
			case 188 : number = true  ; break; 
			case 189 : number = true  ; break; 
			case 190 : number = true  ; break; 
			case 191 : number = true  ; break; 
			case 192 : number = true  ; break; 
			case 193 : number = true  ; break; 
			case 194 : number = true  ; break; 
			case 11 : number = true  ; break; 

		}
		return number ;
	}


}