package com.palacesun.engine.test;

import bean.DataBase;
import bean.Schema;
import bean.View;
import com.palacesun.engine.common.StatementInformation;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.palacesun.masking.tools.EngineUtil;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
import util.JdbcCacheUtil;
import util.JdbcUtil;

public class DbCache {
   private final ReadWriteLock lock;
   private Set<String> names;
   static final Pattern VALID_PATTERN = Pattern.compile("^\\s*((select)|(with)|(insert)|(update)|(delete)|(replace)|(merge))", 10);

   public static final DbCache instance() {
      return DbCacheInstanceHolder.INSTANCE;
   }

   private DbCache() {
      this.names = new HashSet(4);
      this.lock = new ReentrantReadWriteLock(true);
   }

   public void cache(Properties properties, String url) {
      DbMeta meta = this.getDbMeta(properties, url);
      String identifier = meta.getIdentifier();

      try {
         this.lock.readLock().lock();
         if (this.names.contains(identifier)) {
            return;
         }
      } finally {
         this.lock.readLock().unlock();
      }

      try {
         this.lock.writeLock().lock();
         if (!this.names.contains(identifier)) {
            try {
               JdbcUtil.initData(meta.getConfig());
               this.names.add(identifier);
            } catch (Exception e) {
               e.printStackTrace();
            }

            return;
         }
      } finally {
         this.lock.writeLock().unlock();
      }

   }

   private DbMeta getDbMeta(Properties properties, String url) {
      DbMeta meta = new DbMeta();
      meta.url = url;
      int type = 3;
      int from = url.indexOf("://");
      if (from == -1) {
         type = 1;
         from = url.indexOf("@");
      }

      int end = url.indexOf("?");
      String address = end == -1 ? url.substring(from + type) : url.substring(from + type, end);
      int idx = address.lastIndexOf("/");
      if (type == 1) {
         idx = address.lastIndexOf(":");
      }

      if (url.contains("jdbc:sqlserver")) {
         idx = address.indexOf(";");
      }

      meta.host = idx == -1 ? address : address.substring(0, idx);
      if (url.contains("oracle")) {
         int oidx = address.indexOf("/");
         if (oidx != -1) {
            meta.host = address.substring(0, oidx);
         }
      }

      meta.username = properties.getProperty("user");
      meta.password = properties.getProperty("password");
      String dbType = "mysql";
      String lowerUrl = url.toLowerCase();
      if (url.contains("jdbc:mysql")) {
         dbType = "mysql";
      } else if (url.contains("jdbc:oracle")) {
         dbType = "oracle";
      } else if (url.contains("jdbc:dm")) {
         dbType = "dm";
      } else if (url.contains("jdbc:db2")) {
         dbType = "db2";
      } else if (url.contains("jdbc:kingbase")) {
         dbType = "kingbase";
      } else if (!url.contains("jdbc:hive") && !url.contains("jc:inceptor2") && !url.contains("jdbc:transwarp2")) {
         if (url.contains("jdbc:sqlserver")) {
            dbType = "sql server";
         } else if (url.contains("jdbc:postgresql")) {
            if (url.contains("gauss")) {
               dbType = "gauss";
            } else if (url.contains("greenplum")) {
               dbType = "greenplum";
            } else {
               dbType = "postgresql";
            }
         } else if (url.contains("jdbc:vastbase")) {
            dbType = "postgresql";
         } else if (url.contains("jdbc:vertica")) {
            dbType = "vertica";
         }
      } else {
         dbType = "hive";
      }

      meta.dbType = dbType;
      return meta;
   }

   public static boolean isNeedIntercept(String sql, StatementInformation statementInformation) {
      boolean needSqlParse = isNeedSqlParse(sql, statementInformation);
      if (!needSqlParse) {
         return false;
      } else {
         return sql != null && sql.length() != 0 ? VALID_PATTERN.matcher(sql).find() : false;
      }
   }

   public static boolean isNeedSqlParse(String sql, StatementInformation statementInformation) {
      if (statementInformation.isNeedSqlParse() != null) {
         return statementInformation.isNeedSqlParse();
      } else if (sql != null && sql.length() != 0) {
         if (!EngineUtil.encryptionTableSet.contains("dbview")) {
            Set<String> viewSet = new HashSet();
            int size = JdbcCacheUtil.dataBaseList.size();

            for(int i = 0; i < size; ++i) {
               DataBase dataBase = (DataBase)JdbcCacheUtil.dataBaseList.get(i);
               List<Schema> schemaList = dataBase.getSchemaList();

               for(int v = 0; v < schemaList.size(); ++v) {
                  List<View> viewList = ((Schema)schemaList.get(v)).getViewList();

                  for(int s = 0; s < viewList.size(); ++s) {
                     View view = (View)viewList.get(s);

                     for(String tableName : EngineUtil.encryptionTableSet) {
                        if (view != null && view.getCreate_sql() != null && view.getCreate_sql().toLowerCase().contains(tableName)) {
                           viewSet.add(view.getName().toLowerCase());
                           break;
                        }
                     }
                  }
               }
            }

            EngineUtil.encryptionTableSet.addAll(viewSet);
            EngineUtil.encryptionTableSet.add("dbview");
         }

         for(String tableName : EngineUtil.encryptionTableSet) {
            if (sql.toLowerCase().contains(tableName)) {
               statementInformation.setNeedSqlParse(true);
               return true;
            }
         }

         statementInformation.setNeedSqlParse(false);
         return false;
      } else {
         statementInformation.setNeedSqlParse(false);
         return false;
      }
   }

   public void cacheRefresh(Properties properties, String url) {
      DbMeta meta = this.getDbMeta(properties, url);

      try {
         JdbcUtil.refreshData(meta.getConfig());
      } catch (Exception e) {
         e.printStackTrace();
      }

   }

   public static void main(String[] args) {
      DbCache dbCache = new DbCache();
      String url = "jdbc:sqlserver://192.168.2.118:1433;DatabaseName=ry;";
      dbCache.getDbMeta((Properties)null, url);
   }

   static class DbCacheInstanceHolder {
      static final DbCache INSTANCE = new DbCache();
   }

   class DbMeta {
      String url;
      String host;
      String username;
      String password;
      String dbType;

      public String getIdentifier() {
         return String.format("%s:%s:%s:%s", this.host, this.username, this.password, this.dbType);
      }

      public String getConfig() {
         JSONObject db = new JSONObject();
         db.put((String)"ip_port", this.host);
         db.put((String)"url", this.url);
         db.put((String)"username", this.username);
         db.put((String)"password", this.password);
         db.put((String)"dbType", this.dbType);
         JSONArray excludeSchema = new JSONArray();
         if (this.dbType.equalsIgnoreCase("mysql")) {
            excludeSchema.add("information_schema");
            excludeSchema.add("mysql");
            excludeSchema.add("performance_schema");
            excludeSchema.add("sys");
         }

         if (this.dbType.equalsIgnoreCase("kingbase")) {
            excludeSchema.add("pg_show_all_settings");
         }

         db.put((String)"excludeSchema", excludeSchema);
         return db.toString();
      }
   }
}
