package com.platform.service.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import com.platform.dao.IRegionalismCodeDao;
import com.platform.dao.ISystemCodeDao;
import com.platform.dao.PreDataInfoDao;
import com.platform.entities.PreDataInfo;
import com.platform.entities.RegionalismEntity;
import com.platform.entities.SystemEntity;
import com.platform.form.PagerOptions;
import com.platform.service.IPreDataInfoService;
import com.platform.utils.BeanCopy;
import com.platform.utils.Configs;
import com.platform.utils.Constant;
import com.platform.utils.DateForm;
import com.platform.utils.excelUtils.ExcelOperation;

@Service(value = "preDataInfoService")
public class PreDataInfoServiceImpl implements IPreDataInfoService {
	
	public final static Logger log = Configs.DAILY_ROLLING_LOGGER.getLogger(PreDataInfoServiceImpl.class);
	
	@Resource(name = "preDataInfoDao")
	private PreDataInfoDao preDataInfoDao;
	
	@Resource(name = "systemCodeDao")
	private ISystemCodeDao systemCodeDao;
	
	@Resource(name = "regionalismCodeDao")
	private IRegionalismCodeDao regionalismCodeDao;

	@Override
	public List<PreDataInfo> findAll() throws Exception {
		List<PreDataInfo> result = preDataInfoDao.findAll();
		Map<String, String> sqlFilePathsStandard = new HashMap<String, String>();
		sqlFilePathsStandard = getAllFile(sqlFilePathsStandard,
				Configs.SQL_SCRIPT_PATH_STANDARD);
		setScript(result, sqlFilePathsStandard);
		for (PreDataInfo preDataInfo : result) {
			preDataInfo.reSetWorkRange(new ArrayList<String>());
			preDataInfo.setSqlList(new ArrayList<String>());
		}
		return result;
	}

	@Override
	public List<PreDataInfo> findByParam(PagerOptions op) {
		List<PreDataInfo> result = null;
		result = preDataInfoDao.getLimitedDataInfoEntities(op);
		return result;
	}

	@Override
	public Map<String, List> importExcel(List<String> paths) throws Exception {
		Map<String, List> errmap = new HashMap<String, List>();
		List<String> errArea = new ArrayList<String>();
		List<String> errFile = new ArrayList<String>();
		// 待增加的
		List<PreDataInfo> all2Insert = new ArrayList<PreDataInfo>();
		//excel读出的 所有
		List<PreDataInfo> all = new ArrayList<PreDataInfo>();
		//excel读出的 所有修改操作的数据
		List<PreDataInfo> list4Update = new ArrayList<PreDataInfo>();
		//excel读出的 所有新增地区操作的数据
		List<PreDataInfo> list4AddArea = new ArrayList<PreDataInfo>();
		//excel读出的 所有新增系统操作的数据
		List<PreDataInfo> list4AddSystem = new ArrayList<PreDataInfo>();
		for (String filePath : paths) {
			// file.temp 文件存在？ 存在则删除 file，且读入 file.temp
			//读取完后删除源文件（不管是否成功导入）
			XSSFWorkbook workbook = null;
			File tmpf = new File(filePath + ".temp");
			File f = new File(filePath);
			// file.temp 文件存在
			if (tmpf.exists()) {
				//删除 file
				workbook = new XSSFWorkbook(tmpf);
			}
			else {
				if (!f.exists()) {
					log.error(filePath + "  文件 不存在! ");
					errFile.add(f.getName());
					continue;
				}
				else {
					workbook = new XSSFWorkbook(f);
				}
			}
			//Excel导入
			try {
				PreDataInfo pre = new PreDataInfo();
				//excel数据  --> java bean
				List<PreDataInfo> subPreData = ExcelOperation.readExcel4Update(workbook,  Constant.EXCEL_TEMPLATE_INIT_ROW, 0, pre, "id", "dataId", "workRange","sysCode","updateTime","userTablespaceStatus", "checkoutIndicateStatus", "checkoutPayStatus", "userTablespacePath", "checkoutIndicatePath", "checkoutPayPath", "sqlList", "dataVersion", "collectingTime", "collUpdate");
				if (null != subPreData && subPreData.size() > 0) {
					// 是否是 同一个县区的 系统--是则 加入
					boolean isSameArea = true;
					String areaCode = subPreData.get(0).getAreaCode();
					for (PreDataInfo preDataInfo : subPreData) {
						if (!areaCode.equals(preDataInfo.getAreaCode())) {
							// TODO 不是同一个地区：  isSameArea = false;
//							isSameArea = false;
							errArea.add(areaCode);
							break;
						}
					}
					// 是同一个地区，则将 excel中的 待 操作的数据 全加载 到 all 里面
					if (isSameArea) {
						all.addAll(subPreData);
					}
				}
			} catch (Exception e) {
				log.error(e);
			}
//			finally{
//				if (null != workbook) {
//					workbook.close();
//				}
//			}
		}
		
		if (errFile.size() > 0) {
			errmap.put("fileUnExist",errFile);
		}
		if (errArea.size() > 0) {
			errmap.put("areaUnImport", errArea);
		}
		//根据 操作 类别 分类（修改， 新增行政区划，新增信息系统）
		if (all.size() > 0) {
			for (PreDataInfo preDataInfo : all) {
				String updateType = preDataInfo.getIsupdate();
				switch (updateType) 
				{
					case Constant.preDataInfo_add_system:
						list4AddSystem.add(preDataInfo);
						break;
						
					case Constant.preDataInfo_add_area:
						list4AddArea.add(preDataInfo);
						break;
						
					case Constant.preDataInfo_update:
						list4Update.add(preDataInfo);
						break;
	
					default:
						break;
				}
			}
		}
		//TODO 查 地区 是否没有-（没有则添加新地区）：
		if (list4AddArea.size() > 0) {
			this.addArea(list4AddArea);
		}
		//在 pre_data_info表中 新增 操作为（新增行政区划）的系统 -- start
		List<PreDataInfo> allAreaInsert = new ArrayList<PreDataInfo>();
		List<String> sysNamesArea = new ArrayList<String>();
		for (PreDataInfo preDataInfo : list4AddArea) {
			sysNamesArea.add(preDataInfo.getSysName());
		}
		//查询系统的code。
		List<SystemEntity> listSystem = new ArrayList<SystemEntity>();
		Map<String, Integer> syscodeMap = new HashMap<String, Integer>();
		// 去掉 已经导入的系统。。（例如 excel反复导入）
		//在 pre_data_info表中 新增 操作为（新增行政区划）的系统
		allAreaInsert = removeRepeat(list4AddArea);
		if (allAreaInsert.size() > 0) {
			list4AddSystem.addAll(allAreaInsert);
		}
		// 查系统 是否没有-（没有则在 pre_data_info添加新系统）：
		if (list4AddSystem.size() > 0) {
			this.AddSystem(list4AddSystem);
			List<String> sysNames = new ArrayList<String>(); 
			for (PreDataInfo preDataInfo : list4AddSystem) {
				sysNames.add(preDataInfo.getSysName());
			}
			listSystem = new ArrayList<SystemEntity>();
			if (sysNames.size() > 0) {
				listSystem = systemCodeDao.findByName(sysNames);
			}
			syscodeMap = new HashMap<String, Integer>();
			for (SystemEntity systemEntity : listSystem) {
				syscodeMap.put(systemEntity.getSystemName(), systemEntity.getCode());
			}
			for ( PreDataInfo systemEntity : list4AddSystem) {
				PreDataInfo systemFull = new PreDataInfo();
				BeanCopy.copyBean(systemEntity, systemFull);
				systemFull.setSysCode(syscodeMap.get(systemFull.getSysName()));
				systemFull.setUpdateTime(DateForm.date2StringBysecond(new Date()));
				all2Insert.add(systemFull);
			}
		}
		//去掉 已经导入的系统。。（例如 excel反复导入）
		//在 pre_data_info表中 新增 操作为（新增信息系统）的系统
		all2Insert = removeRepeat(all2Insert);
		if (all2Insert.size() > 0) {
			insertBatch(all2Insert);
		}
		
		//在 pre_data_info表中 新增 操作为（新增行政区划）的系统 -- end
		//在 pre_data_info表中 更新 操作为 (修改) 的系统
		if (list4Update.size() > 0) {
			// 待修改的
			List<PreDataInfo> allUpdate = new ArrayList<PreDataInfo>();
			// 查询系统 code 
			for (PreDataInfo preDataInfo : list4Update) {
				sysNamesArea.add(preDataInfo.getSysName());
			}
			//查询系统的code。
			List<SystemEntity> listSystem4Update = new ArrayList<SystemEntity>();
			if (sysNamesArea.size() > 0) {
				listSystem4Update = systemCodeDao.findByName(sysNamesArea);
			}
			for (SystemEntity systemEntity : listSystem4Update) {
				syscodeMap.put(systemEntity.getSystemName(), systemEntity.getCode());
			}
			for (PreDataInfo preUpdate : list4Update) {
				PreDataInfo UpdateFull = new PreDataInfo();
				BeanCopy.copyBean(preUpdate, UpdateFull);
				
				UpdateFull.setSysCode(syscodeMap.get(UpdateFull.getSysName()));
				UpdateFull.setUpdateTime(DateForm.date2StringBysecond(new Date()));
				allUpdate.add(UpdateFull);
			}
			// 更新
			for (PreDataInfo preEntity : allUpdate) {
				try{
					preDataInfoDao.update(preEntity);
				}
				catch(Exception e){
					log.error(e);
				}
			}
		}
		return errmap;
	}
	
	@Override
		public Map<String, List> exportExcel(String path) throws Exception {
			Map<String, List> map = new HashMap<String, List>();
			List<String> errList = new ArrayList<String>();
			List<PreDataInfo> list = findAll();
			ClassPathResource res = new ClassPathResource(Constant.SYSTEM_INFO_EXCEL_TEMPLATE_FIEL_PATH);
			//此处 耗时太久：（原因：excel 2007 以后采用的方式不同造成的建议升级 到 poi 3.15以上）
			XSSFWorkbook workbook = null;
			XSSFWorkbook result = null;
			try {
				workbook = new XSSFWorkbook(res.getInputStream());
				result = ExcelOperation.writeExcelTemplate(workbook, Constant.EXCEL_TEMPLATE_INIT_ROW, 0, 25, list, "id", "dataId", "workRange","sysCode","updateTime","userTablespaceStatus", "checkoutIndicateStatus", "checkoutPayStatus", "userTablespacePath", "checkoutIndicatePath", "checkoutPayPath", "sqlList", "dataVersion", "collectingTime", "collUpdate");
			} catch (Exception e) {
				errList.add(e.getMessage());
			}
			//不能进行close,
			FileOutputStream fileOut = null;
			try {
				File f = new File(path);
				f.createNewFile();
				fileOut = new FileOutputStream(f);
				result.write(fileOut);
			} catch (IOException e) {
				errList.add(e.getMessage());
			}
			finally{
				if (null != fileOut) {
					fileOut.close();
				}
			}
			if (errList.size() > 0) {
				map.put("err", errList);
			}
			return map;
		}

	/** 给system_info增加新系统
	 * @param list4AddSystem
	 * @return
	 * @throws Exception
	 */
	private int AddSystem(List<PreDataInfo> list4AddSystem) throws Exception {
		int insertNum = 0;
		// 查系统 是否没有-（没有则添加新系统）：
		List<String> sysNames = new ArrayList<String>(); 
		for (PreDataInfo preDataInfo : list4AddSystem) {
			sysNames.add(preDataInfo.getSysName());
		}
		//  判断-是否存在该系统
		if (sysNames.size() > 0) {
			//数据库 已存在的  系统
			List<SystemEntity> listSystem = systemCodeDao.findByName(sysNames);
			List<String> existSysNames = new ArrayList<String>(); 
			if (null != listSystem) {
				for ( SystemEntity systemEntity : listSystem) {
					existSysNames.add(systemEntity.getSystemName());
				}
				sysNames.removeAll(existSysNames);
			}
			////数据库 不存在的  系统-（添加新系统）
			if (sysNames.size() > 0) {
				systemCodeDao.insertBatch(sysNames);
				insertNum = sysNames.size();
			}
		}
		return insertNum;
	}
	
	/** 新增地区
	 * @param list4AddArea 待新增地区的列表
	 * @return
	 * @throws Exception
	 */
	private int addArea(List<PreDataInfo> list4AddArea)throws Exception {
		int insertNum = 0;
		List<String> areacodeList = new ArrayList<String>();
		Map<String,RegionalismEntity> areaMap = new HashMap<String, RegionalismEntity>();
		for (PreDataInfo preDataInfo : list4AddArea) {
			areacodeList.add(preDataInfo.getAreaCode().toLowerCase());
			RegionalismEntity region = new RegionalismEntity();
			region.setCode(preDataInfo.getAreaCode().toLowerCase());
			region.setCityName(preDataInfo.getCityName());
			region.setDistrictName(preDataInfo.getDistrictName());
			areaMap.put(region.getCode().toLowerCase(), region);
		}
		List<RegionalismEntity> existEntity = regionalismCodeDao.findExistRegionalism(areacodeList);
		for (RegionalismEntity regionalismEntity : existEntity) {
			areaMap.remove(regionalismEntity.getCode());
		}
		//新增 地区
		if (areaMap.size() > 0) {
			List<RegionalismEntity> insert2Regionalism = new ArrayList<RegionalismEntity>();
			for ( String key : areaMap.keySet()) {
				insert2Regionalism.add(areaMap.get(key));
			}
			if (insert2Regionalism.size() > 0) {
				try {
					regionalismCodeDao.insertBatch(insert2Regionalism);
				} catch (Exception e) {
					log.error(" --    regionalismCodeDao.insertBatch()   ---  error ");
				}
				insertNum = insert2Regionalism.size();
			}
		}
		return insertNum;
	}
	

	/**
	 * 遍历文件
	 * 
	 * @param ps must not null 
	 * @param path
	 * @return
	 */
	private Map<String, String> getAllFile(Map<String, String> ps, String path) {
		File f = new File(path);
		String name = f.getName();
		// 如果是 sql文件
		if (name.endsWith(".sql") || name.endsWith(".SQL"))
			ps.put(name.toLowerCase(), f.getAbsolutePath());
		if (f.exists()) {
			String[] subpaths = f.list();
			if (null != subpaths) {
				for (String tmppath : subpaths) {
					getAllFile(ps, f.getAbsolutePath() + "/" + tmppath);
				}
			}
		}
		return ps;
	}

	/** 设置脚本信息
	 * @param systemDataInfo
	 * @param sqlFilePathsStandard
	 * @return
	 */
	private List<PreDataInfo> setScript(List<PreDataInfo> systemDataInfo,
			Map<String, String> sqlFilePathsStandard) {
		List<PreDataInfo> fileEntitys = new ArrayList<PreDataInfo>();
		for (PreDataInfo preDataInfo : systemDataInfo) {
			// 归档表空间脚本的位置-
			String TablePathStandard = getFilePath("UserTablespace_",
					sqlFilePathsStandard, preDataInfo, ".sql");
			if (null != TablePathStandard && !"".equals(TablePathStandard)) {
				preDataInfo.setUserTablespaceStatus("是");
				preDataInfo.setUserTablespacePath("UserTablespace_"+preDataInfo.getAreaCode()+"_" + preDataInfo.getSysCode()+ ".sql");
			}
			// 归档预算 脚本的位置-
			String indicatePathStandard = getFilePath("Checkout_Indicate_",
					sqlFilePathsStandard, preDataInfo, ".sql");
			if (null != indicatePathStandard && !"".equals(indicatePathStandard)) {
				preDataInfo.setCheckoutIndicateStatus("是");
				preDataInfo.setCheckoutIndicatePath("Checkout_Indicate_"+preDataInfo.getAreaCode()+"_" + preDataInfo.getSysCode()+ ".sql");
			}
			// 归档表空间脚本的位置-
			String payPathStandard = getFilePath("Checkout_Pay_",
					sqlFilePathsStandard, preDataInfo, ".sql");
			if (null != payPathStandard && !"".equals(payPathStandard)) {
				preDataInfo.setCheckoutPayStatus("是");
				preDataInfo.setCheckoutPayPath("Checkout_Pay_"+preDataInfo.getAreaCode()+"_" + preDataInfo.getSysCode()+ ".sql");
			}
			// 设置 状态
			String type = preDataInfo.getDataBaseType().toUpperCase();
			if (!"ORACLE".equals(type)) {
				preDataInfo.setUserTablespaceStatus("-");
			} 
			fileEntitys.add(preDataInfo);
		}
		return fileEntitys;
	}
	
	/**
	 * 查找文件
	 * 
	 * @param prefix
	 * @param map
	 * @param myf
	 * @param affix
	 * @return
	 */
	private String getFilePath(String prefix, Map<String, String> map,
			PreDataInfo pre, String affix) {
		StringBuffer sb = new StringBuffer();
		sb.append(prefix).append(pre.getAreaCode()).append("_")
				.append(pre.getSysCode()).append(affix);
		String fileName = sb.toString().toLowerCase();
		if (!map.containsKey(fileName)) {
			return null;
		}
		// 地区字母 小写 -- 文件属性小写
		String pathStandard = map.get(fileName);
		return pathStandard;
	}
	
	/** 新增系统时，去掉系统已存在的  新增操作里的
	 * @param allAreaInsert
	 * @throws Exception
	 */
	private List<PreDataInfo> removeRepeat(List<PreDataInfo> allAreaInsert) throws Exception {
		Map<String, PreDataInfo> excelAdd = new HashMap<String, PreDataInfo>();
		List<PreDataInfo> allResult = new ArrayList<PreDataInfo>();
		//系统已存在的 系统
		List<PreDataInfo> sysInDataBase = preDataInfoDao.findAll();
		Map<String, String> sysInDataBaseMap = new HashMap<String, String>();
		for (PreDataInfo preDataInfo : sysInDataBase) {
			sysInDataBaseMap.put(preDataInfo.getAreaCode()+"_"+preDataInfo.getSysName().trim(), null);
		}
		//本次新增的系统
		for (PreDataInfo pre : allAreaInsert) {
			if (null == pre.getSysName() || "".equals(pre.getSysName())) {
				continue;
			}
			excelAdd.put(pre.getAreaCode()+"_"+pre.getSysName().trim(), pre);
		}
		Set<String> keys = excelAdd.keySet();
		if (null != keys) {
			for (String key : keys) {
				if (!sysInDataBaseMap.containsKey(key)) {
					allResult.add(excelAdd.get(key));
				}
			}
		}
		return allResult;
	}
	
	/** 批量插入--一次限定多少个(将allAreaInsert 分成 设定大小的 集合)  比如 allAreaInsert 有 100个， 按照 11个为一个集合分，可分成 10个集合
	 * @param allAreaInsert 
	 */
	private void insertBatch(List<PreDataInfo> allAreaInsert) {
		if (allAreaInsert.size() > 0) {
			int listSize = allAreaInsert.size();
			int loopSize = listSize/Configs.NUM_ONE_IMPORT_EXCEL;
			if (loopSize * Configs.NUM_ONE_IMPORT_EXCEL != listSize) {
				loopSize++;
			}
			List<PreDataInfo>[] list = new ArrayList[loopSize];
			for (int i = 0; i < loopSize; i++) {
				list[i] = new ArrayList<PreDataInfo>();
			}
			for (int i = 0; i < listSize; i++) {
				list[i%loopSize].add(allAreaInsert.get(i));
			}
			for (List<PreDataInfo> arrayList : list) {
				try {
					preDataInfoDao.insertBatch(arrayList);
				} catch (Exception e) {
					log.error(e.getStackTrace());
				}
			}
		}
	}
	
}
