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.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class SparkTool {
   private Connection connection;
   private Statement statement;
   private boolean releaseConnection;
   private boolean releaseStatement;

   public SparkTool(DataBase database) {
      try {
         this.connection = DriverManager.getConnection(database.getUrl(), database.getUsername(), database.getPassword());
         this.releaseConnection = true;
      } catch (SQLException e) {
         e.printStackTrace();
      }

   }

   public SparkTool(Connection connection) {
      this.connection = connection;
   }

   public SparkTool(Statement statement) {
      this.statement = statement;
   }

   public SparkTool(Connection connection, Statement statement) {
      this.connection = connection;
      this.statement = statement;
   }

   public List<Schema> getMetaInfo() throws SQLException {
      return this.loadDatabase((DataBase)null);
   }

   public List<Schema> getPlainDbSchemas() throws SQLException {
      List<Schema> schema = this.getSchemas();
      return (List<Schema>)(schema == null ? new ArrayList() : schema);
   }

   public List<Table> getPlainDbTables() throws SQLException {
      List<Table> allTables = new ArrayList();

      for(Schema schema : this.getSchemas()) {
         List<Table> tables = this.getTables(schema.getName());
         if (tables != null) {
            allTables.addAll(tables);
         }
      }

      return allTables;
   }

   public List<Table> getPlainSchemaTables(String schema, String tableNamePattern) throws SQLException {
      this.statement = this.getStatement();
      List<Table> tables = this.getTables(schema, tableNamePattern);
      return (List<Table>)(tables == null ? new ArrayList() : tables);
   }

   public List<View> getPlainSchemaViews(String schema) throws SQLException {
      List<View> views = this.getViews(schema);
      return (List<View>)(views == null ? new ArrayList() : views);
   }

   public List<Column> getPlainTableColumns(String schema, String tableName) throws SQLException {
      this.statement = this.getStatement();
      List<Column> columns = this.getColumns(schema, tableName);
      return (List<Column>)(columns == null ? new ArrayList() : columns);
   }

   private List<Schema> getSchemas() throws SQLException {
      this.statement = this.getStatement();
      List<Schema> schemas = new ArrayList();
      String sql = "show schemas";
      ResultSet resultSet = this.statement.executeQuery(sql);

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

      return schemas;
   }

   private List<Table> getTables(String schema) throws SQLException {
      return this.getTables(schema, null, true);
   }

   private List<Table> getTables(String schema, String pattern) throws SQLException {
      return this.getTables(schema, pattern, true);
   }

   private List<Table> getTables(String schema, String pattern, boolean refresh) throws SQLException {
      this.statement = this.getStatement();
      List<Table> tables = new ArrayList();
      if (refresh) {
         this.refreshContext(schema);
      }

      String sql = "show tables";
      if (pattern != null && pattern.length() > 0) {
         sql = sql + " like %" + pattern + "%";
      }

      ResultSet resultSet = this.statement.executeQuery(sql);

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

      return tables;
   }

   private List<Column> getColumns(String schema, String table) throws SQLException {
      return this.getColumns(schema, table, true);
   }

   private List<Column> getColumns(String schema, String table, boolean refresh) throws SQLException {
      this.statement = this.getStatement();
      List<Column> columns = new ArrayList();
      if (refresh) {
         this.refreshContext(schema);
      }

      String sql = "desc table " + table;
      ResultSet resultSet = this.statement.executeQuery(sql);

      while(resultSet.next()) {
         Column column = new Column(resultSet.getString("COL_NAME"), schema, table, resultSet.getString("DATA_TYPE"));
         column.setColumnType(column.getDataType());
         column.setRemark(resultSet.getString("COMMENT"));
         columns.add(column);
      }

      resultSet.close();
      return columns;
   }

   private List<View> getViews(String schema) throws SQLException {
      return this.getViews(schema, true);
   }

   private List<View> getViews(String schema, boolean refresh) throws SQLException {
      this.statement = this.getStatement();
      List<View> views = new ArrayList();
      if (refresh) {
         this.refreshContext(schema);
      }

      String sql = "show views";
      ResultSet resultSet = this.statement.executeQuery(sql);

      while(resultSet.next()) {
         String tableName = resultSet.getString("VIEWNAME");
         views.add(new View(tableName, null));
      }

      for(View view : views) {
         ResultSet viewResultSet = this.statement.executeQuery("show create table " + view.getName());
         String viewDDL = null;
         boolean next = viewResultSet.next();
         if (next) {
            try {
               viewDDL = viewResultSet.getString(1);
               view.setCreate_sql(viewDDL);
            } catch (SQLException e) {
               e.printStackTrace();
            }
         }
      }

      return views;
   }

   private void refreshContext(String schema) throws SQLException {
      this.statement = this.getStatement();
      this.statement.execute("use " + schema);
   }

   public List<Schema> loadDatabase(DataBase dataBase) throws SQLException {
      List<Schema> schemaList = this.getSchemas();

      for(Schema schema : schemaList) {
         this.statement.execute("use " + schema.getName());
         String schemaName = schema.getRealName();
         if (dataBase == null || !dataBase.getExcludeSchema().contains(schemaName)) {
            List<Table> tableList = this.getTables(schemaName, null, false);
            schema.setTableList(tableList);

            for(Table table : tableList) {
               List<Column> columnList = this.getColumns(schemaName, table.getRealName(), false);
               table.setColumnList(columnList);
            }

            List<View> viewList = this.getViews(schemaName, false);
            schema.setViewList(viewList);
            schema.setSynonymList(new ArrayList());
         }
      }

      return schemaList;
   }

   public void close() {
      if (this.statement != null && this.releaseStatement) {
         try {
            this.statement.close();
         } catch (SQLException throwables) {
            throwables.printStackTrace();
         }

         this.statement = null;
      }

      if (this.connection != null && this.releaseConnection) {
         try {
            this.connection.close();
         } catch (SQLException throwables) {
            throwables.printStackTrace();
         }
      }

      this.connection = null;
   }

   private Statement getStatement() throws SQLException {
      if (this.statement == null && this.connection == null) {
         throw new SQLException("沒有有效的链接传入，connection或者statement至少有个已传入。");
      } else {
         if (this.statement == null) {
            this.statement = this.connection.createStatement();
            this.releaseStatement = true;
         }

         return this.statement;
      }
   }

   public static void main(String[] args) throws SQLException {
      Connection connection = DriverManager.getConnection("jdbc:hive2://192.168.245.30:10000", "", "");
      SparkTool tool = new SparkTool(connection);
      System.out.println("-----------schemas--------------");

      for(Schema item : tool.getPlainDbSchemas()) {
         System.out.println(item.getName());
      }

      System.out.println("-----------db tables--------------");

      for(Table item : tool.getPlainDbTables()) {
         System.out.println(item.getName());
      }

      System.out.println("-----------schema tables--------------");

      for(Table item : tool.getPlainSchemaTables("ry", null)) {
         System.out.println(item.getName());
      }

      System.out.println("-----------schema views--------------");

      for(View item : tool.getPlainSchemaViews("ry")) {
         System.out.println(item.getName());
      }

      System.out.println("-----------table columns--------------");

      for(Column item : tool.getPlainTableColumns("ry", "person")) {
         System.out.println(item.getColumnName());
      }

   }
}
