package util.getdata;

import bean.Column;
import bean.DataBase;
import bean.Schema;
import bean.Synonym;
import bean.Table;
import bean.View;
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;

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

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

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

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

   }

   public List<Schema> cacheToMemory() throws SQLException {
      this.connection = JdbcCacheUtil.getDmConnection(this.DataBase.getUrl(), this.DataBase.getUsername(), this.DataBase.getPassword());
      this.statement = this.connection.createStatement();
      List<Schema> schemaList = this.init(this.statement);
      return schemaList;
   }

   public List<Schema> getSchema(Statement statement) throws SQLException {
      List<Schema> schemaList = new ArrayList();
      String sql = "select distinct OBJECT_NAME TABLE_SCHEMA from all_objects where object_type = 'SCH'";
      ResultSet resultSet = statement.executeQuery(sql);

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

      resultSet.close();
      return schemaList;
   }

   public List<Table> getTable(Statement statement, String schema) throws SQLException {
      List<Table> tableList = new ArrayList();
      String sql = "select TABLE_NAME from dba_tables where owner='" + schema + "' and TABLESPACE_NAME<>'TEMP'";
      ResultSet resultSet = statement.executeQuery(sql);

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

      resultSet.close();
      return tableList;
   }

   public List<Column> getColumn(Statement statement, String schema, String table) throws SQLException {
      List<Column> columnList = new ArrayList();
      String sql = "  select \t\n\ta.owner,\n\ta.table_name,\n\ta.column_name,\n\ta.data_type,\n\ta.data_length as length,\n\ta.data_precision as scale,\t\n\tcase when instr(a.data_type,'(')>0 then a.data_type else a.data_type || '(' || a.data_length || (\n\t\tcase when a.data_precision is null then '' else ',' || a.data_precision end \n\t) || ')' end as column_type , '' as remark, nvl(c.pk,0) pk\nfrom all_tab_columns A\nLEFT JOIN (\n select A.OWNER,A.TABLE_NAME,B.COLUMN_NAME,1 PK from \"SYS\".\"DBA_CONSTRAINTS\" a \n left join \"SYS\".\"DBA_CONS_COLUMNS\" b \n on a.OWNER=b.OWNER AND a.CONSTRAINT_NAME=a.CONSTRAINT_NAME\n and a.table_name=b.table_name\n where a.constraint_type='P'\n)C on a.owner=c.owner and a.table_name=c.table_name and a.column_name=c.column_name\n where a.owner='" + schema + "' and a.Table_Name='" + table + "'";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         Column column = new Column();
         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("PK"));
         columnList.add(column);
      }

      resultSet.close();
      return columnList;
   }

   public List<View> getView(Statement statement, String schema) throws SQLException {
      List<View> views = new ArrayList();
      String sql = "select VIEW_NAME ,TEXT from DBA_VIEWS where OWNER = '" + schema + "'";
      ResultSet resultSet = statement.executeQuery(sql);

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

      resultSet.close();
      return views;
   }

   public List<Synonym> getSynonym(Statement statement, String schema) throws SQLException {
      List<Synonym> synonyms = new ArrayList();
      String sql = "SELECT SYNONYM_NAME , TABLE_NAME FROM DBA_SYNONYMS WHERE TABLE_OWNER = '" + schema + "'";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String SYNONYM_NAME = resultSet.getString("SYNONYM_NAME");
         String TABLE_NAME = resultSet.getString("TABLE_NAME");
         synonyms.add(new Synonym(SYNONYM_NAME, TABLE_NAME));
      }

      resultSet.close();
      return synonyms;
   }

   public List<Schema> init(Statement statement) throws SQLException {
      List<Schema> schemas = this.getSchema(statement);
      if (schemas != null && schemas.size() != 0) {
         List<Table> tables = this.getTables(statement);
         List<View> views = this.getViews(statement);
         List<Synonym> synonyms = this.getSynonyms(statement);

         for(Schema schema : schemas) {
            List<Table> tbs = new ArrayList();

            for(Table x : tables) {
               if (x.getSchema().equals(schema.getName())) {
                  tbs.add(x);
               }
            }

            schema.setTableList(tbs);
            List<View> vws = new ArrayList();

            for(View x : views) {
               if (x.getSchema().equals(schema.getName())) {
                  vws.add(x);
               }
            }

            schema.setViewList(vws);
            List<Synonym> syns = new ArrayList();

            for(Synonym x : synonyms) {
               if (x.getSchema().equals(schema.getName())) {
                  syns.add(x);
               }
            }

            schema.setSynonymList(syns);
         }

         return (List<Schema>)(schemas == null ? new ArrayList() : schemas);
      } else {
         return new ArrayList();
      }
   }

   public List<View> getViews(Statement statement) throws SQLException {
      List<View> views = new ArrayList();
      String sql = "select OWNER,VIEW_NAME ,TEXT from DBA_VIEWS";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String schema = resultSet.getString("OWNER");
         String table_name = resultSet.getString("VIEW_NAME");
         String view_definition = resultSet.getString("TEXT").replaceAll("`", "");
         views.add(new View(schema, table_name, view_definition));
      }

      resultSet.close();
      return views;
   }

   public List<Synonym> getSynonyms(Statement statement) throws SQLException {
      List<Synonym> synonyms = new ArrayList();
      String sql = "SELECT OWNER, SYNONYM_NAME , TABLE_NAME FROM DBA_SYNONYMS  ";
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String SYNONYM_NAME = resultSet.getString("SYNONYM_NAME");
         String TABLE_NAME = resultSet.getString("TABLE_NAME");
         String SCHEMA_NAME = resultSet.getString("OWNER");
         synonyms.add(new Synonym(SCHEMA_NAME, TABLE_NAME, SYNONYM_NAME));
      }

      resultSet.close();
      return synonyms;
   }

   public List<Table> getTables(Statement statement) throws SQLException {
      new ArrayList();
      String sql = "  select \t\n\ta.owner,\n\ta.table_name,\n\ta.column_name,\n\ta.data_type,\n\ta.data_length as length,\n\ta.data_precision as scale,\t\n\tcase when instr(a.data_type,'(')>0 then a.data_type else a.data_type || '(' || a.data_length || (\n\t\tcase when a.data_precision is null then '' else ',' || a.data_precision end \n\t) || ')' end as column_type , '' as remark, nvl(c.pk,0) pk\nfrom all_tab_columns A\nleft join (\n select distinct A.OWNER,A.TABLE_NAME,B.COLUMN_NAME,1 PK from \"SYS\".\"DBA_CONSTRAINTS\" a \n left join \"SYS\".\"DBA_CONS_COLUMNS\" b \n on a.OWNER=b.OWNER and a.CONSTRAINT_NAME=a.CONSTRAINT_NAME\n and a.table_name=b.table_name\n where a.constraint_type='P'\n)C on a.owner=c.owner and a.table_name=c.table_name and a.column_name=c.column_name\norder by a.owner,a.table_name,a.column_id\n";
      List<Table> tables = new ArrayList();
      Table table = null;
      ResultSet resultSet = statement.executeQuery(sql);

      while(resultSet.next()) {
         String schema = resultSet.getString("OWNER");
         String tableName = resultSet.getString("TABLE_NAME");
         if (table == null || !table.getName().equals(tableName) || !table.getSchema().equals(schema)) {
            table = new Table(tableName, schema);
            table.setRealName(tableName);
            table.setColumnList(new ArrayList());
            tables.add(table);
         }

         Column column = new Column();
         column.setSchema(schema);
         column.setTable(tableName);
         column.setColumnName(resultSet.getString("COLUMN_NAME"));
         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("PK"));
         table.getColumnList().add(column);
      }

      resultSet.close();
      return tables;
   }
}
