package util.getdata;

import bean.Column;
import bean.DataBase;
import bean.Schema;
import bean.Table;
import bean.View;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import util.JdbcCacheUtil;
import util.StringJoin;

public class CacheMysql extends CacheData {
   public CacheMysql(DataBase DataBase, CountDownLatch cdl) {
      super(DataBase, cdl);
   }

   public void run() {
      System.out.println("mysql开始缓存");

      try {
         this.cacheWriteToRedis();
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            JdbcCacheUtil.closeConnection(this.connection);
            if (this.statement != null) {
               this.statement.close();
            }
         } catch (Exception throwables) {
            throwables.printStackTrace();
         }

         this.getCdl().countDown();
         System.out.println("mysql结束缓存");
      }

   }

   public List<Schema> cacheToMemory() throws SQLException, ClassNotFoundException {
      this.connection = JdbcCacheUtil.getConnection(this.DataBase.getUrl(), this.DataBase.getUsername(), this.DataBase.getPassword());
      this.statement = this.connection.createStatement();
      List<Schema> schemaList = this.getSchema(this.statement);
      List<Table> tableList = this.getTables(this.statement, schemaList);
      List<Column> columns = this.getColumns(this.statement, schemaList, tableList);

      for(Schema schema : schemaList) {
         List<Table> newTableList = new ArrayList();

         for(Table table : tableList) {
            if (table.getSchema().equals(schema.getName())) {
               newTableList.add(table);
            }
         }

         schema.setTableList(newTableList);

         for(Table table : schema.getTableList()) {
            List<Column> newColumnList = new ArrayList();

            for(Column column : columns) {
               if (column.getTable().equals(table.getName()) && column.getSchema().equals(schema.getName())) {
                  newColumnList.add(column);
               }
            }

            table.setColumnList(newColumnList);
         }

         List<View> viewList = this.getView(this.statement, schema.getName());
         schema.setViewList(viewList);
      }

      return schemaList;
   }

   private List<Table> getTables(Statement statement, List<Schema> schemas) throws SQLException {
      List<String> schemaNameList = new ArrayList();

      for(Schema schema : schemas) {
         if (schema != null && schema.getName().length() > 0) {
            schemaNameList.add(schema.getName());
         }
      }

      String schemasWhere = StringJoin.join(schemaNameList, "','");
      String sql = "select TABLE_NAME,TABLE_SCHEMA from information_schema.tables where TABLE_TYPE = 'BASE TABLE' AND table_schema in ('" + schemasWhere + "')";
      List<Table> tables = new ArrayList();
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String schema = resultSet.getString("TABLE_SCHEMA");
         Table table = new Table(resultSet.getString("TABLE_NAME"), schema);
         table.setRealName(resultSet.getString("TABLE_NAME"));
         tables.add(table);
      }

      resultSet.close();
      return tables;
   }

   private List<Column> getColumns(Statement statement, List<Schema> schemas, List<Table> tables) throws SQLException {
      List<String> schemaNameList = new ArrayList();

      for(Schema schema : schemas) {
         if (schema != null && schema.getName().length() > 0) {
            schemaNameList.add(schema.getName());
         }
      }

      List<String> tableNameList = new ArrayList();

      for(Table table : tables) {
         if (table != null && table.getName().length() > 0) {
            tableNameList.add(table.getName());
         }
      }

      String schemasWhere = StringJoin.join(schemaNameList, "','");
      String tablesWhere = StringJoin.join(tableNameList, "','");
      String sql = "select COLUMN_NAME,DATA_TYPE,TABLE_SCHEMA,TABLE_NAME,COLUMN_TYPE,IFNULL(CHARACTER_MAXIMUM_LENGTH,IFNULL(NUMERIC_PRECISION,DATETIME_PRECISION)) AS LENGTH, (CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN NUMERIC_SCALE ELSE NULL END ) AS SCALE,COLUMN_COMMENT as REMARK ,(CASE WHEN COLUMN_KEY IS NOT NULL AND COLUMN_KEY='PRI' THEN 1 ELSE 0 END) AS IS_PK  from information_schema.columns  where TABLE_SCHEMA in( '" + schemasWhere + "') and TABLE_NAME in ('" + tablesWhere + "')  ORDER BY ordinal_position";
      List<Column> columns = new ArrayList();
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         Column column = new Column();
         String schema = resultSet.getString("TABLE_SCHEMA");
         String table = resultSet.getString("TABLE_NAME");
         column.setColumnName(resultSet.getString("COLUMN_NAME"));
         column.setSchema(schema);
         column.setTable(table);
         column.setDataType(resultSet.getString("DATA_TYPE"));
         column.setColumnType(resultSet.getString("COLUMN_TYPE"));
         column.setLength(resultSet.getObject("LENGTH") + "");
         Object scale = resultSet.getObject("SCALE");
         column.setDigits(scale == null ? "" : scale.toString());
         String remark = resultSet.getString("REMARK");
         column.setRemark(remark == null ? "" : remark);
         column.setPk(resultSet.getInt("IS_PK"));
         columns.add(column);
      }

      resultSet.close();
      return columns;
   }

   private void setCase(Connection connection, DataBase dataBase) {
      Statement statement = null;
      ResultSet resultSet = null;

      try {
         statement = connection.createStatement();
         resultSet = statement.executeQuery("select @@lower_case_table_names");
         boolean next = resultSet.next();
         if (next) {
            Object object = resultSet.getObject(1);
            if (object != null) {
               dataBase.setCaseSensitive("0".equalsIgnoreCase(object.toString()));
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         if (statement != null) {
            try {
               statement.close();
            } catch (SQLException throwables) {
               throwables.printStackTrace();
            }
         }

         if (resultSet != null) {
            try {
               resultSet.close();
            } catch (SQLException throwables) {
               throwables.printStackTrace();
            }
         }

      }

   }

   public void toUppercase(List<Schema> schemaList) {
      for(Schema schema : schemaList) {
         for(Table table : schema.getTableList()) {
            for(Column column : table.getColumnList()) {
               if (!this.isEmpty(column.getColumnName())) {
                  column.setColumnName(column.getColumnName());
               }
            }

            if (!this.isEmpty(table.getName())) {
               table.setName(table.getName());
            }
         }

         for(View view : schema.getViewList()) {
            if (!this.isEmpty(view.getName())) {
               view.setName(view.getName());
            }
         }

         if (!this.isEmpty(schema.getName())) {
            schema.setName(schema.getName());
         }
      }

   }

   public List<Schema> getSchema(Statement statement) throws SQLException {
      List<Schema> schemas = new ArrayList();
      String sql = "select SCHEMA_NAME from information_schema.schemata";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         Schema schema = new Schema(resultSet.getString("SCHEMA_NAME"));
         schema.setRealName(resultSet.getString("SCHEMA_NAME"));
         schemas.add(schema);
      }

      resultSet.close();
      return schemas;
   }

   public List<Table> getTable(Statement statement, String schema) throws SQLException {
      List<Table> tables = new ArrayList();
      String sql = "select TABLE_NAME from information_schema.tables where TABLE_TYPE = 'BASE TABLE' AND table_schema='" + schema + "'";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         Table table = new Table(resultSet.getString("TABLE_NAME"), schema);
         table.setRealName(resultSet.getString("TABLE_NAME"));
         tables.add(table);
      }

      resultSet.close();
      return tables;
   }

   public List<Column> getColumn(Statement statement, String schema, String table) throws SQLException {
      List<Column> columns = new ArrayList();
      String sql = "select a.COLUMN_NAME,a.DATA_TYPE,a.COLUMN_TYPE,(CASE WHEN A.COLUMN_KEY IS NOT NULL AND a.COLUMN_KEY='PRI' THEN 1 ELSE 0 END) AS IS_PK from information_schema.columns a where TABLE_SCHEMA = '" + schema + "' and TABLE_NAME = '" + table + "'  ORDER BY ordinal_position";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         Column column = new Column(resultSet.getString("COLUMN_NAME"), schema, table, resultSet.getString("DATA_TYPE"));
         column.setDataType(resultSet.getString("COLUMN_TYPE"));
         column.setPk(resultSet.getInt("IS_PK"));
         columns.add(column);
      }

      resultSet.close();
      return columns;
   }

   public List<View> getView(Statement statement, String schema) throws SQLException {
      List<View> views = new ArrayList();
      String sql = "select TABLE_NAME,VIEW_DEFINITION from information_schema.VIEWS where TABLE_SCHEMA = '" + schema + "'";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String table_name = resultSet.getString("TABLE_NAME");
         String view_definition = resultSet.getString("VIEW_DEFINITION").replaceAll("`", "");
         views.add(new View(table_name, view_definition));
      }

      resultSet.close();
      return views;
   }

   private boolean isEmpty(String str) {
      return str == null || str.length() == 0;
   }
}
