package com.palacesun.engine.spy;

import com.palacesun.engine.common.ConnectionInformation;
import com.palacesun.engine.common.P6LogQuery;
import com.palacesun.engine.event.JdbcEventListener;
import com.palacesun.engine.gateway.EncryptionGatewayManager;
import com.palacesun.engine.test.DbCache;
import com.palacesun.engine.wrapper.ConnectionWrapper;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.regex.Pattern;

public class MaskingDriver implements Driver {
   static Boolean cacheDatabase = false;
   private static Driver instance = new MaskingDriver();
   private static JdbcEventListenerFactory jdbcEventListenerFactory;

   public boolean acceptsURL(String url) {
      String pattern = "(jdbc:masking:.*)|(java:comp/env/masking:.*)|(java:jboss/masking/.*)";
      boolean matches = Pattern.compile(pattern).matcher(url).matches();
      return url != null && matches;
   }

   public boolean acceptsRealURL(String url) {
      if (!url.contains("masking")) {
         EncryptionGatewayManager.logDatabaseUrl(url);
         return false;
      } else {
         String pattern = "(jdbc:.*)|(java:comp/env/.*)|(java:jboss/.*)";
         boolean matches = Pattern.compile(pattern).matcher(url).matches();
         return url != null && matches;
      }
   }

   private String extractRealUrl(String url) {
      if (url.indexOf("java:jboss/masking/") != -1) {
         return url.replace("java:jboss/masking/", "java:jboss/");
      } else {
         return this.acceptsURL(url) ? url.replace("masking:", "") : url;
      }
   }

   static List<Driver> registeredDrivers() {
      List<Driver> result = new ArrayList();
      Enumeration<Driver> driverEnumeration = DriverManager.getDrivers();

      while(driverEnumeration.hasMoreElements()) {
         result.add(driverEnumeration.nextElement());
      }

      return result;
   }

   public Connection connect(String url, Properties properties) throws SQLException {
      if (url == null) {
         throw new SQLException("url is required");
      } else if (!this.acceptsRealURL(url)) {
         return null;
      } else {
         EncryptionGatewayManager.logDatabaseUrl(url);
         Driver passThru = this.findPassthru(url);
         P6LogQuery.debug("this is " + this + " and passthru is " + passThru);
         long start = System.nanoTime();
         if (jdbcEventListenerFactory == null) {
            jdbcEventListenerFactory = JdbcEventListenerFactoryLoader.load();
         }

         JdbcEventListener jdbcEventListener = jdbcEventListenerFactory.createJdbcEventListener();
         ConnectionInformation connectionInformation = ConnectionInformation.fromDriver(passThru);
         connectionInformation.setUrl(url);

         try {
            jdbcEventListener.onBeforeGetConnection(connectionInformation);
         } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new SQLException(e);
         }

         String extractRealUrl = this.extractRealUrl(url);

         Connection conn;
         try {
            conn = passThru.connect(extractRealUrl, properties);
            connectionInformation.setConnection(conn);
            connectionInformation.setTimeToGetConnectionNs(System.nanoTime() - start);
            jdbcEventListener.onAfterGetConnection(connectionInformation, (SQLException)null);
         } catch (SQLException e) {
            EncryptionGatewayManager.logClientError("获取数据库连接失败： " + e.getMessage());
            connectionInformation.setTimeToGetConnectionNs(System.nanoTime() - start);
            jdbcEventListener.onAfterGetConnection(connectionInformation, e);
            throw e;
         }

         DbCache.instance().cache(properties, extractRealUrl);

         try {
            return ConnectionWrapper.wrap(conn, jdbcEventListener, connectionInformation);
         } catch (Exception e) {
            throw new SQLException(e);
         }
      }
   }

   private String getIpPortByUrl(String url) {
      String host = null;
      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(";");
      }

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

      return host;
   }

   protected Driver findPassthru(String url) throws SQLException {
      P6ModuleManager.getInstance();
      StringBuilder sb = new StringBuilder();

      for(Driver driver : registeredDrivers()) {
         if (driver == null) {
            sb.append("null\n");
         } else {
            sb.append(driver.getClass().getName()).append("\n");
         }
      }

      String realUrl = this.extractRealUrl(url);
      Driver passthru = null;

      for(Driver driver : registeredDrivers()) {
         try {
            if (driver.acceptsURL(this.extractRealUrl(url))) {
               passthru = driver;
               break;
            }
         } catch (SQLException e) {
            e.printStackTrace();
         }
      }

      if (passthru == null) {
         try {
            P6RegisterDriver.register(url);
         } catch (Exception var8) {
            throw new SQLException("Unable to find a driver that accepts register failed" + realUrl);
         }

         for(Driver driver : registeredDrivers()) {
            try {
               if (driver.acceptsURL(this.extractRealUrl(url))) {
                  passthru = driver;
                  break;
               }
            } catch (SQLException e) {
               EncryptionGatewayManager.logClientError("加载数据库驱动失败" + e.getMessage());
               e.printStackTrace();
            }
         }
      }

      if (passthru == null) {
         throw new SQLException("Unable to find a driver that accepts " + realUrl);
      } else {
         return passthru;
      }
   }

   public DriverPropertyInfo[] getPropertyInfo(String url, Properties properties) throws SQLException {
      return this.findPassthru(url).getPropertyInfo(url, properties);
   }

   public int getMajorVersion() {
      return 12;
   }

   public int getMinorVersion() {
      return 0;
   }

   public boolean jdbcCompliant() {
      return true;
   }

   public Logger getParentLogger() throws SQLFeatureNotSupportedException {
      throw new SQLFeatureNotSupportedException("Feature not supported");
   }

   public static void setJdbcEventListenerFactory(JdbcEventListenerFactory jdbcEventListenerFactory) {
      MaskingDriver.jdbcEventListenerFactory = jdbcEventListenerFactory;
   }

   static {
      try {
         DriverManager.registerDriver(instance);
      } catch (SQLException e) {
         throw new IllegalStateException("Could not register P6SpyDriver with DriverManager", e);
      }
   }
}
