package com.chenyang.nse.bussiness.service.core.impl;

import com.chenyang.nse.bussiness.dao.PageInfo;
import com.chenyang.nse.bussiness.dao.table.core.blobmasking.TCoreBlobMaskingTaskDao;
import com.chenyang.nse.bussiness.entity.orm.table.core.blobmasking.TCoreBlobMaskingTask;
import com.chenyang.nse.bussiness.entity.param.blobmasking.TCoreBlobMaskingTaskCond;
import com.chenyang.nse.bussiness.entity.vo.ResultVO;
import com.chenyang.nse.bussiness.entity.vo.blobmasking.TCoreBlobMaskingTaskVO;
import com.chenyang.nse.bussiness.service.core.BlobMaskingTaskService;
import com.chenyang.nse.bussiness.service.core.DataSystemService;
import com.chenyang.nse.bussiness.tools.datatime.DateTimeTool;
import com.chenyang.nse.bussiness.tools.jdbc.JdbcTool;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Pattern;
import oracle.sql.BLOB;
import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;

@Service
@Transactional
public class BlobMaskingTaskServiceImpl implements BlobMaskingTaskService {
   private static Logger logger = LoggerFactory.getLogger(BlobMaskingTaskServiceImpl.class);
   @Autowired
   TCoreBlobMaskingTaskDao tCoreBlobMaskingTaskDao;
   @Autowired
   private DataSystemService dataSystemService;
   private Connection conn;
   public int erroCnt = 0;

   public Connection getConn(String dataSourceId) throws Exception {
      this.conn = this.dataSystemService.getConnectionByDataSystemId(dataSourceId);
      return this.conn;
   }

   public void setExecutionState(String taskid) {
      TCoreBlobMaskingTask tCoreBlobMaskingTask = (TCoreBlobMaskingTask)this.tCoreBlobMaskingTaskDao.get(taskid);
      tCoreBlobMaskingTask.setIsRunState("1");
      this.tCoreBlobMaskingTaskDao.update(tCoreBlobMaskingTask);
   }

   public ResultVO execMaskingTask(String taskid) {
      ResultVO rv = new ResultVO("创建失败", false);
      TCoreBlobMaskingTask tCoreBlobMaskingTask = (TCoreBlobMaskingTask)this.tCoreBlobMaskingTaskDao.get(taskid);

      try {
         if (null != tCoreBlobMaskingTask) {
            TCoreBlobMaskingTaskCond tcbmCond = new TCoreBlobMaskingTaskCond();
            tcbmCond.setTaskname(tCoreBlobMaskingTask.getTaskname());
            tcbmCond.setTaskNote(tCoreBlobMaskingTask.getTaskNote());
            tcbmCond.setDataSourceid(tCoreBlobMaskingTask.getDataSourceid());
            tcbmCond.setBschema(tCoreBlobMaskingTask.getBschema());
            tcbmCond.setTablename(tCoreBlobMaskingTask.getTablename());
            tcbmCond.setFieldname(tCoreBlobMaskingTask.getFieldname());
            tcbmCond.setMaskrange(tCoreBlobMaskingTask.getMaskrange());
            if (null != tcbmCond.getMaskrange()) {
               String[] rangeArr = tcbmCond.getMaskrange().split(",");
               if (null != rangeArr && rangeArr.length > 4) {
                  tcbmCond.getRangeMap();
                  HashMap<String, String> rangeMap = new HashMap();
                  rangeMap.put("nameFlg", rangeArr[0]);
                  rangeMap.put("ageFlg", rangeArr[1]);
                  rangeMap.put("genderFlg", rangeArr[2]);
                  rangeMap.put("admissiontimeFlg", rangeArr[3]);
                  rangeMap.put("ethnicFlg", rangeArr[4]);
                  tcbmCond.setRangeMap(rangeMap);
                  this.readAndMaskingBlob(tcbmCond);
               }
            }
         }

         rv.setMessage("创建成功");
         rv.setResult(true);
      } catch (Exception e) {
         e.printStackTrace();
         rv.setMessage(e.getMessage());
         rv.setResult(false);
      } finally {
         tCoreBlobMaskingTask.setIsRunState("0");
         this.tCoreBlobMaskingTaskDao.update(tCoreBlobMaskingTask);
         return rv;
      }
   }

   public void readAndMaskingBlob11(TCoreBlobMaskingTaskCond tcbmCond) throws Exception {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;

      try {
         conn = this.getConn(tcbmCond.getDataSourceid());
         new ArrayList();
         List<String> e = JdbcTool.getPK(conn, (String)null, tcbmCond.getBschema(), tcbmCond.getTablename());
         String pkQueryStr = "";
         if (null != e && e.size() > 0) {
            for(int i = 0; i < e.size(); ++i) {
               pkQueryStr = pkQueryStr + (String)e.get(i) + ",";
            }
         }

         tcbmCond.setPkList(e);
         tcbmCond.setPkQueryStr(pkQueryStr);
         System.out.println(DateTimeTool.getSysTime("===============query table pk is" + pkQueryStr + "======================"));
         StringBuffer querySql = new StringBuffer();
         querySql.append("SELECT ");
         querySql.append(pkQueryStr + " ");
         querySql.append(tcbmCond.getFieldname() + " ");
         querySql.append("FROM ");
         querySql.append(tcbmCond.getBschema() + "." + tcbmCond.getTablename() + " ");
         querySql.append("WHERE 1=1 FOR UPDATE");
         System.out.println(DateTimeTool.getSysTime("") + "=================query Blob data start======================");
         System.out.println(DateTimeTool.getSysTime("") + "=================query Blob data sql:" + querySql.toString() + "======================");
         ps = conn.prepareStatement(querySql.toString());
         rs = ps.executeQuery();
         System.out.println(DateTimeTool.getSysTime("") + "=================query Blob data end======================");
         conn.setAutoCommit(false);

         while(rs.next()) {
            int readIdx = 1;
            String newStr = "";
            List<String> pkValList = new ArrayList();
            String pkValueStr = "";

            for(int i = 0; i < e.size(); ++i) {
               Object blobObj = rs.getObject((String)e.get(i));
               if (null != blobObj) {
                  pkValList.add(blobObj.toString());
                  pkValueStr = pkValueStr + blobObj.toString() + ",";
               }
            }

            tcbmCond.setPkValList(pkValList);
            tcbmCond.setPkValueStr(pkValueStr);
            Object blobObj = rs.getObject(tcbmCond.getFieldname());
            if (null != blobObj) {
               BLOB blob = (BLOB)blobObj;
               long BlobLength = blob.length();
               if (BlobLength > 0L) {
                  while((long)readIdx < BlobLength) {
                     byte[] bytes = blob.getBytes((long)readIdx, 1024);
                     readIdx += 1024;
                     newStr = newStr + new String(bytes, "UTF-8");
                  }

                  if (StringUtils.isNotBlank(newStr)) {
                     String reXmlStr = this.maskingInfo(newStr, tcbmCond);
                     if (StringUtils.isNotBlank(reXmlStr)) {
                        byte[] reXmlByteArr = reXmlStr.getBytes("UTF-8");
                        InputStream in = new ByteArrayInputStream(reXmlByteArr);
                        OutputStream out = blob.getBinaryOutputStream();
                        byte[] buffer = new byte[1024];
                        int length = -1;

                        while((length = in.read(buffer)) != -1) {
                           out.write(buffer, 0, length);
                        }

                        out.close();
                        in.close();
                        conn.commit();
                     }
                  }
               }
            }
         }

         conn.setAutoCommit(true);
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         if (null != ps) {
            ps.close();
         }

         if (null != rs) {
            rs.close();
         }

         if (null != conn) {
            conn.close();
         }

      }

   }

   public void readAndMaskingBlob(TCoreBlobMaskingTaskCond tcbmCond) {
      Connection conn = null;
      PreparedStatement selectPkPs = null;
      PreparedStatement updateBlobPs = null;
      ResultSet rs = null;

      try {
         conn = this.getConn(tcbmCond.getDataSourceid());
         new ArrayList();
         List<String> e = JdbcTool.getPK(conn, (String)null, tcbmCond.getBschema(), tcbmCond.getTablename());
         String pkQueryStr = "";
         if (null != e && e.size() > 0) {
            for(int i = 0; i < e.size(); ++i) {
               pkQueryStr = pkQueryStr + (String)e.get(i) + ",";
            }
         }

         tcbmCond.setPkList(e);
         tcbmCond.setPkQueryStr(pkQueryStr);
         if (!e.isEmpty()) {
            String selectPkSql = "select " + (String)e.get(0) + " , " + tcbmCond.getFieldname() + " from " + tcbmCond.getBschema() + "." + tcbmCond.getTablename() + " where " + tcbmCond.getFieldname() + " IS NOT NULL";
            selectPkPs = conn.prepareStatement(selectPkSql);
            rs = selectPkPs.executeQuery();
            String updateBlobSql = "update " + tcbmCond.getBschema() + "." + tcbmCond.getTablename() + " set " + tcbmCond.getFieldname() + " = ? where " + (String)e.get(0) + " = ?";

            while(rs.next()) {
               List<String> pkValList = new ArrayList();
               String pkValueStr = "";

               for(int i = 0; i < e.size(); ++i) {
                  Object blobObj = rs.getObject((String)e.get(i));
                  if (null != blobObj) {
                     pkValList.add(blobObj.toString());
                     pkValueStr = pkValueStr + blobObj.toString() + ",";
                  }
               }

               tcbmCond.setPkValList(pkValList);
               tcbmCond.setPkValueStr(pkValueStr);
               String blobStr = new String(rs.getBytes(tcbmCond.getFieldname()));
               if (StringUtils.isNotBlank(blobStr)) {
                  String reblobStr = this.maskingInfo(blobStr, tcbmCond);
                  if (StringUtils.isNotBlank(reblobStr)) {
                     updateBlobPs = conn.prepareStatement(updateBlobSql);
                     updateBlobPs.setBytes(1, reblobStr.getBytes("UTF-8"));
                     updateBlobPs.setString(2, rs.getString((String)e.get(0)));
                     updateBlobPs.executeUpdate();
                     updateBlobPs.close();
                  }
               }
            }

            return;
         }
      } catch (Exception e) {
         e.printStackTrace();
         return;
      } finally {
         try {
            if (rs != null) {
               rs.close();
            }

            if (selectPkPs != null) {
               selectPkPs.close();
            }

            JdbcTool.closeConnection(conn);
         } catch (SQLException e) {
            e.printStackTrace();
         }

      }

   }

   public String maskingInfo(String xmlStr, TCoreBlobMaskingTaskCond tcbmCond) throws Exception {
      HashMap<String, String> rangeMap = tcbmCond.getRangeMap();
      String reXmlStr = "";
      Document document = null;
      try {
         return reXmlStr;
      } catch (Exception e) {
         StringBuffer erroMsg = new StringBuffer();
         this.erroCnt++;
         erroMsg.append(this.erroCnt + tcbmCond.getTablename() + ",");
         erroMsg.append(tcbmCond.getPkQueryStr() + "");
         erroMsg.append(tcbmCond.getPkValueStr() + "");
         erroMsg.append(tcbmCond.getFieldname() + "\n");
         erroMsg.append(" \n" + xmlStr);
         return reXmlStr;
      } finally {
         Exception exception = null;
         if (null != document) {
            Element root = document.getRootElement();
            List<Node> fieldelemlist = root.selectNodes("//fieldelem");
            if (fieldelemlist.size() > 0 && fieldelemlist != null && null != rangeMap)
               for (int i = 0; i < fieldelemlist.size(); i++) {
                  Element fieldelem = (Element)fieldelemlist.get(i);
                  String code = fieldelem.attributeValue("code");
                  String value = fieldelem.getTextTrim();
                  if (code.equals("HR02.01.002") && "1".equals(rangeMap.get("nameFlg")))
                     fieldelem.setText(getMaskingName(value));
                  if (code.equals("DE02.01.026.00") && "1".equals(rangeMap.get("ageFlg")))
                     fieldelem.setText(getMaskingAge(value));
                  if (code.equals("HR02.02.001") && "1".equals(rangeMap.get("genderFlg")))
                     fieldelem.setText(getMaskingGender(value));
                  if (code.equals("DE06.00.092.00") && "1".equals(rangeMap.get("admissiontimeFlg")))
                     fieldelem.setText(getMaskingHospitalization(value));
                  if (code.equals("HR02.05.001") && "1".equals(rangeMap.get("ethnicFlg")))
                     fieldelem.setText(getMaskingEthnic(value));
               }
            reXmlStr = document.asXML();
            reXmlStr = reXmlStr.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", "");
         }
      }
   }

   public String getTempRoot(String xmlStr) {
      String reXmlStr = "";
      if (StringUtils.isNotBlank(xmlStr)) {
         String rootBeginStr = "<TEMPROOT>";
         String rootEndStr = "</TEMPROOT>";
         int beginIdx = xmlStr.indexOf("<CDR>");
         StringBuilder xmlStrBuffer = new StringBuilder(xmlStr);
         xmlStrBuffer.insert(beginIdx, rootBeginStr);
         int endIdx = xmlStrBuffer.lastIndexOf("</CDR>");
         xmlStrBuffer.insert(endIdx, rootEndStr);
         reXmlStr = xmlStrBuffer.toString();
      }

      return reXmlStr;
   }

   public String getMaskingName(String sourceName) {
      String reName = "";
      if (StringUtils.isNotBlank(sourceName)) {
         reName = sourceName.replace(sourceName.substring(1, sourceName.length()), "*");
      }

      return reName;
   }

   public String getMaskingAge(String sourceAge) {
      String reAge = "";
      if (StringUtils.isNotBlank(sourceAge) && this.isInteger(sourceAge)) {
         Integer igrSourceAge = Integer.valueOf(sourceAge);
         if (igrSourceAge > 10) {
            Integer reAgeInt = Math.round((float)igrSourceAge / 10.0F) * 10;
            reAge = String.valueOf(reAgeInt);
         } else {
            reAge = sourceAge;
         }
      }

      return reAge;
   }

   public boolean isInteger(String str) {
      Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
      return pattern.matcher(str).matches();
   }

   public String getMaskingGender(String sourceGender) {
      String reGender = "";
      if (StringUtils.isNotBlank(sourceGender)) {
         String[] genderArr = new String[]{"男", "女"};
         Random rand = new Random();
         int num = rand.nextInt(2);
         reGender = genderArr[num];
      }

      return reGender;
   }

   public String getMaskingHospitalization(String sourceHospitalization) {
      String reHospitalization = "";
      if (StringUtils.isNotBlank(sourceHospitalization)) {
         Calendar calendar = Calendar.getInstance();
         calendar.set(1990, 11, 31);
         calendar.getTime().getTime();
         calendar.set(11, 0);
         calendar.set(12, 0);
         calendar.set(13, 0);
         long min = calendar.getTime().getTime();
         calendar.set(2018, 1, 31);
         calendar.set(11, 0);
         calendar.set(12, 0);
         calendar.set(13, 0);
         calendar.getTime().getTime();
         long max = calendar.getTime().getTime();
         double randomDate = Math.random() * (double)(max - min) + (double)min;
         calendar.setTimeInMillis(Math.round(randomDate));
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         reHospitalization = format.format(calendar.getTime());
      }

      return reHospitalization;
   }

   public String getMaskingEthnic(String sourceEthnic) {
      String reEthnic = "";
      if (StringUtils.isNotBlank(sourceEthnic)) {
         String[] ethnicArr = new String[]{"汉", "壮", "满", "回", "苗"};
         Random rand = new Random();
         int num = rand.nextInt(5);
         reEthnic = ethnicArr[num];
      }

      return reEthnic;
   }

   public List<TCoreBlobMaskingTask> queryTask(String taskname, PageInfo pageInfo) {
      long count = this.tCoreBlobMaskingTaskDao.count();
      pageInfo.setCount(count);
      List<TCoreBlobMaskingTask> list = this.tCoreBlobMaskingTaskDao.queryByPageInfo(pageInfo, Order.desc("createtime"), new Criterion[]{Restrictions.like("taskname", taskname, MatchMode.ANYWHERE).ignoreCase()});
      return list;
   }

   public List<TCoreBlobMaskingTask> queryBlobMaskingTaskByTaskName(String taskname) {
      List<TCoreBlobMaskingTask> list = this.tCoreBlobMaskingTaskDao.queryAll(new Criterion[]{Restrictions.eq("taskname", taskname)});
      return list;
   }

   public ResultVO saveBlobMaskingTask(TCoreBlobMaskingTaskCond tcbmtc) {
      ResultVO rv = new ResultVO("创建失败", false);
      TCoreBlobMaskingTask tCoreBlobMaskingTask = new TCoreBlobMaskingTask();
      tCoreBlobMaskingTask.setTaskname(tcbmtc.getTaskname());
      tCoreBlobMaskingTask.setTaskNote(tcbmtc.getTaskNote());
      tCoreBlobMaskingTask.setDataSourceid(tcbmtc.getDataSourceid());
      tCoreBlobMaskingTask.setBschema(tcbmtc.getBschema());
      tCoreBlobMaskingTask.setTablename(tcbmtc.getTablename());
      tCoreBlobMaskingTask.setFieldname(tcbmtc.getFieldname());
      tCoreBlobMaskingTask.setMaskrange(tcbmtc.getMaskrange());
      tCoreBlobMaskingTask.setCreatetime(new Date());
      tCoreBlobMaskingTask.setUpdatetime(new Date());
      tCoreBlobMaskingTask.setUserId(tcbmtc.getUserId());
      tCoreBlobMaskingTask.setUsername(tcbmtc.getUsername());
      this.tCoreBlobMaskingTaskDao.save(tCoreBlobMaskingTask);
      rv.setMessage("创建成功");
      rv.setResult(true);
      return rv;
   }

   public void removeTask(String taskid) {
      this.tCoreBlobMaskingTaskDao.removeById(taskid);
   }

   public TCoreBlobMaskingTask queryBlobMaskingTaskByID(String taskid) {
      TCoreBlobMaskingTask tbmTask = (TCoreBlobMaskingTask)this.tCoreBlobMaskingTaskDao.get(taskid);
      return tbmTask;
   }

   public TCoreBlobMaskingTaskVO queryBlobMaskingTaskVOByID(String taskid) {
      TCoreBlobMaskingTaskVO tbmTask = null;
      List<TCoreBlobMaskingTaskVO> taskLst = this.tCoreBlobMaskingTaskDao.queryBlobMaskingTaskVOByID(taskid);
      if (null != taskLst && taskLst.size() > 0) {
         tbmTask = (TCoreBlobMaskingTaskVO)taskLst.get(0);
      }

      return tbmTask;
   }

   public static void main(String[] args) throws Exception {
      System.out.println(DateTimeTool.getSysTime("") + "=================import Blob data start======================");
      writeBlob();
      System.out.println(DateTimeTool.getSysTime("") + "=================import Blob data end======================");
   }

   public static void writeBlob() throws Exception {
      String path = "D:\\blobxml";
      List<String> xmllist = getPathFile(path);
      ResultSet rs = null;
      PreparedStatement ps = null;
      BLOB blob = null;
      boolean flag = false;
      Connection testConn = getConn();

      for(String filename : xmllist) {
         try {
            String id = UUID.randomUUID().toString();
            testConn.setAutoCommit(false);
            String sql = "INSERT INTO masking.EMR_BL_BL02 (blbh,blnr) VALUES( ? ,empty_blob())";
            PreparedStatement var27 = testConn.prepareStatement(sql);
            var27.setString(1, id);
            var27.executeUpdate();
            sql = "SELECT blnr FROM masking.EMR_BL_BL02 WHERE blbh = ? FOR UPDATE";
            ps = testConn.prepareStatement(sql);
            ps.setString(1, id);
            rs = ps.executeQuery();
            if (rs.next()) {
               blob = (BLOB)rs.getBlob(1);
            }

            InputStream in = new FileInputStream(path + "\\" + filename);
            OutputStream out = blob.setBinaryStream(1L);
            byte[] buffer = new byte[1024];
            int length = -1;

            while((length = in.read(buffer)) != -1) {
               out.write(buffer, 0, length);
            }

            in.close();
            out.close();
            testConn.commit();
            testConn.setAutoCommit(true);
            flag = true;
         } catch (Exception e) {
            if (testConn != null) {
               try {
                  testConn.rollback();
               } catch (SQLException e1) {
                  e1.printStackTrace();
               }
            }

            e.printStackTrace();
         } finally {
            try {
               rs.close();
               ps.close();
            } catch (Exception e) {
               e.printStackTrace();
            }

         }
      }

      testConn.close();
   }

   public static List<String> getPathFile(String path) {
      if (null != path && !"".equals(path)) {
         File parent = new File(path);
         if (parent.exists() && !parent.isFile()) {
            File[] list = parent.listFiles();
            if (list != null && list.length != 0) {
               List<String> result = new ArrayList();

               for(File child : list) {
                  if (child.isFile()) {
                     result.add(child.getName());
                  }
               }

               return result;
            } else {
               return null;
            }
         } else {
            return null;
         }
      } else {
         return null;
      }
   }

   public static Connection getConn() throws Exception {
      String driver = "oracle.jdbc.OracleDriver";
      String url = "jdbc:oracle:thin:@//192.168.2.155:1521/orcl";
      String username = "masking";
      String password = "masking";
      Class.forName(driver);
      return DriverManager.getConnection(url, username, password);
   }
}
