package com.platform.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.platform.dao.PreDataInfoDao;
import com.platform.entities.DefaultDataDescription;
import com.platform.entities.PreDataInfo;
import com.platform.entities.SqlFileInfoEntity;
import com.platform.service.IScriptMakeService;
import com.platform.utils.BeanCopy;
import com.platform.utils.Compare4SqlFilesEntity;
import com.platform.utils.Configs;
import com.platform.utils.Constant;
import com.platform.utils.DateForm;
import com.platform.utils.FileOperateHelper;
import com.platform.utils.ThreadRemoveFile;
import com.platform.utils.XmlOperationByDom4j;

@Service(value = "scriptMakeService")
public class ScriptMakeService implements IScriptMakeService {

	@SuppressWarnings("static-access")
	public static Logger log = Configs.DAILY_ROLLING_LOGGER
			.getLogger(ScriptMakeService.class);

	@Resource(name = "preDataInfoDao")
	private PreDataInfoDao preDataInfoDao;

	@Override
	public int makeCfg() throws Exception {
		log.info("makeCfg");
		List<PreDataInfo> systemInfoList = preDataInfoDao.findAll();
		String path = FileOperateHelper
				.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD);
		StringBuffer sb = new StringBuffer();
		sb.append("市\t县（市、区）\t行政区划代码\r\n");
		Map<String, Object> startData = new HashMap<String, Object>();
		for (PreDataInfo preDataInfo : systemInfoList) {
			startData.put(preDataInfo.getAreaCode().toLowerCase(), preDataInfo);

		}
		// 以地区为准--一个地区一个xml
		for (String key : startData.keySet()) {
			PreDataInfo preDataInfo = (PreDataInfo) startData.get(key);
			sb.append(preDataInfo.getCityName());
			sb.append("\t");
			sb.append(preDataInfo.getDistrictName());
			sb.append("\t");
			sb.append(preDataInfo.getAreaCode().toLowerCase());
			sb.append("\r\n");
		}
		FileOperateHelper.fileReWriteGBK(path + Constant.cfgFileName,
				sb.toString());
		log.info("makeCfg--end");
		return 1;
	}

	@Override
	public int makeXml() throws Exception {
		log.info("makeXml");
		List<PreDataInfo> systemInfoList = preDataInfoDao.findAll();
		String dirpath = FileOperateHelper
				.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD);
		Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		for (PreDataInfo preDataInfo : systemInfoList) {
			putSystemByAreaCode(map, preDataInfo.getAreaCode().toLowerCase(), preDataInfo);
		}
		// 一个地区一个xml
		for (String key : map.keySet()) {
			String areaPath = dirpath + key;
			File f = new File(areaPath);
			f.mkdir();
			List<Object> defList = new ArrayList<Object>();
			List<Object> list = map.get(key);
			for (Object object : list) {
				DefaultDataDescription defaul = new DefaultDataDescription();
				defaul.setvalue((PreDataInfo) object);
				defList.add(defaul);
			}

			XmlOperationByDom4j
					.createXml(FileOperateHelper.addLastSeparator(areaPath)
							+ key + ".xml", defList, "Data_info", "id", "dataId","workRange","sysCode","updateTime","userTablespaceStatus", "checkoutIndicateStatus", "checkoutPayStatus", "userTablespacePath", "checkoutIndicatePath", "checkoutPayPath", "sqlList", "dataVersion", "collectingTime", "collUpdate");
		}
		log.info("makeXml--end");
		return 1;
	}

	@Override
	public List<SqlFileInfoEntity> findAllFiles() throws Exception {
		List<PreDataInfo> systemDataInfo = preDataInfoDao.findAll();
		// 查找 Configs.SQL_SCRIPT_PATH_LAST 路径下的 所有的文件：路径
		Map<String, String> sqlFilePathsLast = new HashMap<String, String>();
		Map<String, String> timeMapLast = new HashMap<String, String>();
		sqlFilePathsLast = getAllFile(sqlFilePathsLast,timeMapLast, 
				Configs.SQL_SCRIPT_PATH_LAST);
		// 遍历 查找 Configs.SQL_SCRIPT_PATH_STANDARD 脚本文件 放入集合中
		Map<String, String> sqlFilePathsStandard = new HashMap<String, String>();
		Map<String, String> timeMapStandard = new HashMap<String, String>();
		sqlFilePathsStandard = getAllFile(sqlFilePathsStandard,timeMapStandard, 
				Configs.SQL_SCRIPT_PATH_STANDARD);
		// 填充 脚本状态、位置的信息
		List<SqlFileInfoEntity> result = setScript(systemDataInfo,
				sqlFilePathsStandard, sqlFilePathsLast, timeMapLast, timeMapStandard);
		return result;
	}

	@Override
	public Map<String, Object> readSql(String name, SqlFileInfoEntity form) {
		Map<String, Object> map = new HashMap<String, Object>();
		String path1 = "";
		String path2 = "";
		switch (name) {
			case "userTableStatus":
				path1 = form.getUserTableStatusPathStandard();
				map.put("data1Path", path1);
				map.put("data1", fileReader(path1));
				path2 = form.getUserTableStatusPathLast();
				map.put("data2Path", path2);
				map.put("data2", fileReader(path2));
				break;
			case "ckIndicateStatus":
				path1 = form.getCkIndicateStatusPathStandard();
				map.put("data1Path", path1);
				map.put("data1", fileReader(path1));
				path2 = form.getCkIndicateStatusPathLast();
				map.put("data2Path", path2);
				map.put("data2", fileReader(path2));
				break;
			case "ckPayStatus":
				path1 = form.getCkPayStatusPathStandard();
				map.put("data1Path", path1);
				map.put("data1", fileReader(path1));
				path2 = form.getCkPayStatusPathLast();
				map.put("data2Path", path2);
				map.put("data2", fileReader(path2));
				break;
			default:
				break;
		}
		return map;
	}

	@Override
	public int moveFiles(List<SqlFileInfoEntity> files) throws Exception {

		return 0;
	}

	@Override
	public Map<String, Object> handleSqlFile(String type, String opt, String content, SqlFileInfoEntity form) {
		Map<String, Object> map = new HashMap<String, Object>();
		String standardPath = "";
		String lastPath = "";
		if (null == form.getAreaCode() || form.getSysCode() < 1) {
			map.put("err", "请选择信息系统！");
			return map;
		}
//		选择哪种类型的 脚本  path 可能 = null
		switch (type) {
			case "userTableStatus":
				standardPath = form.getUserTableStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + form.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.UserTablespace + form.getAreaCode().toLowerCase() + "_" + form.getSysCode() + ".sql";
				}
				lastPath = form.getUserTableStatusPathLast();
				break;
			case "ckIndicateStatus":
				standardPath = form.getCkIndicateStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + form.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Indicate + form.getAreaCode().toLowerCase() + "_" + form.getSysCode() + ".sql";
				}
				lastPath = form.getCkIndicateStatusPathLast();
				break;
			case "ckPayStatus":
				standardPath = form.getCkPayStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + form.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Pay + form.getAreaCode().toLowerCase() + "_" + form.getSysCode() + ".sql";
				}
				lastPath = form.getCkPayStatusPathLast();
				break;
			default:
				map.put("err", "请选择脚本类型！");
				break;
		}
		if (map.containsKey("err_opt")) {
			return map;
		}
		switch (opt) {
			// 删除 最新的 脚本  （审核-保留）
			case "delete":  
				fileDelete(lastPath);
				break;
				// 最新脚本 替换 标准脚本（即 以最新脚本为准 ）(归档 或审核-替换)
			case "replace":
				FileOperateHelper.fileReWriteGBK(standardPath, fileReader(lastPath));
				fileDelete(lastPath);
				break;
				//新增 标准的脚本（注意 造出 对应的 standardPath standardPath不能 = null ''）（上传）
			case "add":
				FileOperateHelper.fileReWriteGBK(standardPath,content);
				break;
				// （查看）
			case "read":  
				map = readSql(type, form);
				break;
			default:
				map.put("err", "请选择操作选项！");
				break;
		}
		return map;
	}

	/**
	 * @param map
	 * @param code
	 * @param data
	 * @return
	 */
	private Map<String, List<Object>> putSystemByAreaCode(
			Map<String, List<Object>> map, String code, PreDataInfo data) {
		List<Object> list = map.get(code);
		if (null == list) {
			list = new ArrayList<Object>();
		}
		list.add(data);
		map.put(code, list);
		return map;
	}

	/**
	 * 遍历文件
	 * 
	 * @param ps must not null 
	 * @param path
	 * @return
	 */
	public Map<String, String> getAllFile(Map<String, String> ps, Map<String, String> timeMap,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());
			timeMap.put(name.toLowerCase(), DateForm.date2StringBysecond(new Date(f.lastModified())));
		}
		if (f.exists()) {
			String[] subpaths = f.list();
			if (null != subpaths) {
				for (String tmppath : subpaths) {
					getAllFile(ps, timeMap, f.getAbsolutePath() + "/" + tmppath);
				}
			}
		}
		return ps;
	}

	/**
	 * @param systemDataInfo
	 *            系统信息
	 * @param sqlFilePathsStandard
	 *            标准的-归档的脚本
	 * @param sqlFilePathsLast
	 *            最新的脚本
	 * @return
	 */
	private List<SqlFileInfoEntity> setScript(List<PreDataInfo> systemDataInfo,
			Map<String, String> sqlFilePathsStandard,
			Map<String, String> sqlFilePathsLast,Map<String, String> timeMapLast,
			Map<String, String> timeMapStandard) {
		List<SqlFileInfoEntity> fileEntitys = new ArrayList<SqlFileInfoEntity>();
		for (PreDataInfo preDataInfo : systemDataInfo) {
			SqlFileInfoEntity myfile = new SqlFileInfoEntity();
			// 复制
			BeanCopy.copyBean(preDataInfo, myfile);
			//---------- 脚本的位置  ------
			// 归档表空间脚本的位置-
			String TablePathStandard = getFilePath(Constant.UserTablespace,
					sqlFilePathsStandard, myfile, ".sql");
			myfile.setUserTableStatusPathStandard(TablePathStandard);
			// 归档预算 脚本的位置-
			String indicatePathStandard = getFilePath(Constant.Checkout_Indicate,
					sqlFilePathsStandard, myfile, ".sql");
			myfile.setCkIndicateStatusPathStandard(indicatePathStandard);
			// 归档表空间脚本的位置-
			String payPathStandard = getFilePath(Constant.Checkout_Pay,
					sqlFilePathsStandard, myfile, ".sql");
			myfile.setCkPayStatusPathStandard(payPathStandard);
			// 最新表空间脚本的位置-
			String TablePathLast = getFilePath(Constant.UserTablespace,
					sqlFilePathsLast, myfile, ".sql");
			myfile.setUserTableStatusPathLast(TablePathLast);
			// 最新预算 脚本的位置-
			String indicatePathLast = getFilePath(Constant.Checkout_Indicate,
					sqlFilePathsLast, myfile, ".sql");
			myfile.setCkIndicateStatusPathLast(indicatePathLast);
			// 最新表空间脚本的位置-
			String payPathLast = getFilePath(Constant.Checkout_Pay, sqlFilePathsLast,
					myfile, ".sql");
			myfile.setCkPayStatusPathLast(payPathLast);
			
			//-------文件最后更新-时间-------
		//	时间
			String uttimeStandard = getFilePath(Constant.UserTablespace,
					timeMapStandard, myfile, ".sql");
			myfile.setUserTableStatusStandardModified(uttimeStandard);
			// 归档预算 脚本的时间-
			String indicateTimeStandard = getFilePath(Constant.Checkout_Indicate,
					timeMapStandard, myfile, ".sql");
			myfile.setCkIndicateStatusStandardModified(indicateTimeStandard);
			// 归档表空间脚本的时间-
			String payTimeStandard = getFilePath(Constant.Checkout_Pay,
					timeMapStandard, myfile, ".sql");
			myfile.setCkPayStatusStandardModified(payTimeStandard);
			// 最新表空间脚本的时间-
			String utTimeLast = getFilePath(Constant.UserTablespace,
					timeMapLast, myfile, ".sql");
			myfile.setUserTableStatusLastModified(utTimeLast);
			// 最新预算 脚本的时间-
			String indicateTimeLast = getFilePath(Constant.Checkout_Indicate,
					timeMapLast, myfile, ".sql");
			myfile.setCkIndicateStatusLastModified(indicateTimeLast);
			// 最新表空间脚本的时间-
			String payTimeLast = getFilePath(Constant.Checkout_Pay, timeMapLast,
					myfile, ".sql");
			myfile.setCkPayStatusLastModified(payTimeLast);
			// 设置 状态
			if (null != myfile.getDataBaseType()) {
				if ("ORACLE".equals(myfile.getDataBaseType().toUpperCase())) {
					myfile.setUserTableStatus(getStatus(
							myfile.getUserTableStatusPathStandard(),
							myfile.getUserTableStatusPathLast()));
				} else {
					myfile.setUserTableStatus(4);
				}
			}
			myfile.setCkIndicateStatus(getStatus(
					myfile.getCkIndicateStatusPathStandard(),
					myfile.getCkIndicateStatusPathLast()));
			myfile.setCkPayStatus(getStatus(
					myfile.getCkPayStatusPathStandard(),
					myfile.getCkPayStatusPathLast()));
			myfile.setSysStatus(getTotalStatus(myfile));
			fileEntitys.add(myfile);
		}
//		Compare4SqlFilesEntity com = new Compare4SqlFilesEntity();
//		System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); 
//		Collections.sort(fileEntitys, com);
//		Collections.sort(fileEntitys);
		List<ArrayList<SqlFileInfoEntity>> tmpList = new ArrayList<ArrayList<SqlFileInfoEntity>>();
		for (int i = 0; i < 4; i++) {
			tmpList.add(new ArrayList<SqlFileInfoEntity>());
		}
		
		for (SqlFileInfoEntity sqlFileInfoEntity : fileEntitys) {
			tmpList.get(sqlFileInfoEntity.getSysStatus()).add(sqlFileInfoEntity);
		}
		ArrayList<SqlFileInfoEntity> result = new ArrayList<SqlFileInfoEntity>();
		for (int i = (tmpList.size()-1); i >= 0; i--) {
			result.addAll(tmpList.get(i));
		}
		
		return result;
	}

	/**
	 * 查找文件
	 * 
	 * @param prefix
	 * @param map
	 * @param myf
	 * @param affix
	 * @return
	 */
	private String getFilePath(String prefix, Map<String, String> map,
			SqlFileInfoEntity myf, String affix) {
		StringBuffer sb = new StringBuffer();
		sb.append(prefix).append(myf.getAreaCode().toLowerCase()).append("_")
				.append(myf.getSysCode()).append(affix);
		String fileName = sb.toString().toLowerCase();
		if (!map.containsKey(fileName)) {
			return null;
		}
		// 地区字母 小写 -- 文件属性小写
		String pathStandard = map.get(fileName);
		return pathStandard;
	}

	/**
	 * 返回状态--0： standard, last为空； 1：standard不空，last为空；
	 * 2：standard为空，last不空，3：standard不空，last不空 对应 含义，操作： 0：（有缺失，上传） ； 1： （正常
	 * ，查看）； 2：（待归档，归档） ； 3： （待审核，审核）
	 * 
	 * @param standard
	 * @param last
	 * @return
	 */
	private int getStatus(String standard, String last) {
		int status = 0;
		if (null != standard && !standard.isEmpty()) {
			status = status | 1;
		}
		if (null != last && !last.isEmpty()) {
			status = status | 2;
		}
		return status;
	}

	/**
	 * 返回状态 对应 含义，操作： 0：（有缺失，上传） ； 1： （正常 ，查看）； 2：（待归档，归档） ； 3： （待审核，审核）
	 * 
	 * @param standard
	 * @param last
	 * @return
	 */
	private int getTotalStatus(SqlFileInfoEntity myfile) {
		Integer[] numArr = null;
		Integer result = 1;
		if ("ORACLE".equals(myfile.getDataBaseType().toUpperCase())) {
			numArr = new Integer[3];
			numArr[2]= myfile.getUserTableStatus();
		}
		else {
			numArr = new Integer[2];
		}
		numArr[0]= myfile.getCkPayStatus();
		numArr[1]= myfile.getCkIndicateStatus();
		for (Integer integer : numArr) {
			if (integer != 1) {
				result = integer;
			}
		}
		if (result == 1) {
			return result;
		}
		for (Integer integer : numArr) {
			if (integer != 1) {
				result = result | integer;
			}
		}
		return result;
	}

	private static String fileReader(String path) {
		StringBuffer sb = new StringBuffer();
		if (null == path || "".equals(path)) {
			return sb.toString();
		}
		return FileOperateHelper.fileReaderAndendline(path);
	}

	private static int fileDelete(String path) {
		if (null == path || "".equals(path)) {
			return -1;
		}
		File file = new File(path);
		if (!file.exists())
			return -1;
		if (!file.delete()) {
			ArrayList<String> arr = new ArrayList<String>();
			arr.add(path);
			new ThreadRemoveFile(arr).start();
		}
		return 1;
	}

	@Override
	public Map<String, Object> totalOnholeSqlFile(List<SqlFileInfoEntity> forms) {
		Map<String, Object> errMap = new HashMap<String, Object>();
		List<String> errlist = new ArrayList<String>();
		//待归档  status = 2
		for (SqlFileInfoEntity sqlFile : forms) {
			// 用户表空间脚本
			if (sqlFile.getUserTableStatus() == 2) {
				String standardPath = sqlFile.getUserTableStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.UserTablespace + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getUserTableStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
			// 支付脚本
			if (sqlFile.getCkPayStatus() == 2) {
				String standardPath = sqlFile.getCkPayStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Pay + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getCkPayStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
			// 可执行脚本 
			if (sqlFile.getCkIndicateStatus() == 2) {
				String standardPath = sqlFile.getCkIndicateStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Indicate + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getCkIndicateStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
		}
		if (errlist.size() > 0) {
			errMap.put("nosqlfile", errlist);
		}
		return errMap;
	}

	@Override
	public Map<String, Object> totalVerifySqlFile(List<SqlFileInfoEntity> forms) {
		Map<String, Object> errMap = new HashMap<String, Object>();
		List<String> errlist = new ArrayList<String>();
		//待归档  status = 2
		for (SqlFileInfoEntity sqlFile : forms) {
			// 用户表空间脚本
			if (sqlFile.getUserTableStatus() == 3) {
				String standardPath = sqlFile.getUserTableStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.UserTablespace + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getUserTableStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
			// 支付脚本
			if (sqlFile.getCkPayStatus() == 3) {
				String standardPath = sqlFile.getCkPayStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Pay + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getCkPayStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
			// 可执行脚本 
			if (sqlFile.getCkIndicateStatus() == 3) {
				String standardPath = sqlFile.getCkIndicateStatusPathStandard();
				if (null == standardPath || standardPath.isEmpty()) {
					String spath = FileOperateHelper.addLastSeparator(Configs.SQL_SCRIPT_PATH_STANDARD)  + sqlFile.getAreaCode().toLowerCase();
					File file = new File(spath);
					file.mkdir();
					standardPath = spath + File.separator + Constant.Checkout_Indicate + sqlFile.getAreaCode().toLowerCase() + "_" + sqlFile.getSysCode() + ".sql";
				}
				String lastPath = sqlFile.getCkIndicateStatusPathLast();
				if(!FileOperateHelper.singleFileMove(lastPath, standardPath)){
					errlist.add(lastPath);
				}
			}
		}
		if (errlist.size() > 0) {
			errMap.put("nosqlfile", errlist);
		}
		return errMap;
	}

}
