package util.sqlparse.visitor.common.names;

import bean.Column;
import bean.Schema;
import bean.Table;
import bean.View;
import com.alibaba.druid.DbType;
import com.alibaba.druid.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import util.getdata.DatabaseCache;
import util.sqlparse.visitor.db2.DB2NameWrapper;
import util.sqlparse.visitor.dm.DmNameWrapper;
import util.sqlparse.visitor.gauss.GaussNameWrapper;
import util.sqlparse.visitor.greenplum.GreenplumNameWrapper;
import util.sqlparse.visitor.hive.HiveNameWrapper;
import util.sqlparse.visitor.hivetdh.HiveTDHNameWrapper;
import util.sqlparse.visitor.kingbase.KingbaseNameWrapper;
import util.sqlparse.visitor.mariadb.MariadbNameWrapper;
import util.sqlparse.visitor.mysql.MySQLNameWrapper;
import util.sqlparse.visitor.oracle.OracleNameWrapper;
import util.sqlparse.visitor.postgresql.PostgresqlNameWrapper;
import util.sqlparse.visitor.sqlserver.SQLServerNameWrapper;

public class NameWrapper {
   protected DatabaseCache cache;
   protected boolean isCaseSensitive;
   protected int colDepthInFullColumn = 2;

   public static NameWrapper create(DbType dbType, DatabaseCache cache) {
      NameWrapper wrapper = null;
      switch (dbType) {
         case mysql:
            wrapper = new MySQLNameWrapper(cache);
            break;
         case mariadb:
            wrapper = new MariadbNameWrapper(cache);
            break;
         case oracle:
            wrapper = new OracleNameWrapper(cache);
            break;
         case kingbase:
            wrapper = new KingbaseNameWrapper(cache);
            break;
         case dm:
            wrapper = new DmNameWrapper(cache);
            break;
         case sqlserver:
            wrapper = new SQLServerNameWrapper(cache);
            break;
         case hive_tdh:
            wrapper = new HiveTDHNameWrapper(cache);
            break;
         case hive:
            wrapper = new HiveNameWrapper(cache);
            break;
         case greenplum:
            wrapper = new GreenplumNameWrapper(cache);
            break;
         case postgresql:
            wrapper = new PostgresqlNameWrapper(cache);
            break;
         case db2:
            wrapper = new DB2NameWrapper(cache);
            break;
         case gauss:
            wrapper = new GaussNameWrapper(cache);
            break;
         default:
            wrapper = new NameWrapper(cache);
      }

      return wrapper;
   }

   public NameWrapper(DatabaseCache cache) {
      this.cache = cache;
      this.isCaseSensitive = cache.getDataBase().isCaseSensitive();
   }

   public String unwrapSchema(String schema) {
      return schema != null && schema.length() != 0 ? schema.toUpperCase() : schema;
   }

   public String unwrapTable(String schema, String table) {
      return table != null && table.length() != 0 ? table.toUpperCase() : table;
   }

   public String unwrapFullColumn(Column c) {
      if (c == null) {
         return null;
      } else {
         String column = c.getColumnName();
         return column != null && column.length() != 0 ? column.toUpperCase() : column;
      }
   }

   public void unwrapFullColumns(List<Column> cols) {
      if (cols != null && cols.size() != 0) {
         for(Column col : cols) {
            if (col != null) {
               col.setColumnName(this.unwrapFullColumn(col));
            }
         }

      }
   }

   protected ColInfo getColumnInfo(Column c) {
      String name = c.getColumnName();
      ColInfo col = new ColInfo();
      String cname = name;
      List<String> segs = new ArrayList();

      for(int i = 1; i < this.colDepthInFullColumn; ++i) {
         int idx = cname.indexOf(".");
         if (idx == -1) {
            col.column = name;
            return col;
         }

         segs.add(cname.substring(0, idx));
         cname = cname.substring(idx + 1);
      }

      col.schema = c.getSchema();
      col.table = (String)segs.get(0);
      col.column = cname;
      return col;
   }

   public Table getTable(String schemaName, String tableName) {
      schemaName = schemaName.replace("`", "").replaceAll("\"", "").replaceAll("\\[", "").replaceAll("\\]", "");
      tableName = tableName.replace("`", "").replaceAll("\"", "").replaceAll("\\[", "").replaceAll("\\]", "");
      if (this.cache.getDataBase().isRedis()) {
         Schema schemaFromRedis = this.getSchemaFromRedis(schemaName, this.isCaseSensitive);
         return this.getTableFromRedis(schemaFromRedis, tableName, this.isCaseSensitive);
      } else {
         List<Schema> schemas = this.cache.getDataBase().getSchemaList();
         if (schemas != null && schemas.size() > 0) {
            for(Schema schema : schemas) {
               if (schema.getName().equalsIgnoreCase(schemaName)) {
                  List<Table> tables = schema.getTableList();
                  if (tables != null && tables.size() > 0) {
                     for(Table table : tables) {
                        if (table.getName().equalsIgnoreCase(tableName)) {
                           return table;
                        }
                     }
                  }
               }
            }
         }

         return null;
      }
   }

   protected String unwrapName(String name) {
      return name;
   }

   public View getView(String schema, String viewName) {
      if (this.cache.getDataBase().isRedis()) {
         this.getView(schema, viewName, false);
      }

      return null;
   }

   public View getView(String schema, String viewName, boolean isSensitive) {
      if (this.cache.getDataBase().isRedis()) {
         Schema schemaFromRedis = this.getSchemaFromRedis(schema, isSensitive);
         return this.getViewFromRedis(schemaFromRedis, viewName, isSensitive);
      } else {
         return null;
      }
   }

   public Table getTableFromRedis(Schema sch, String table, boolean isSensitive) {
      table = this.unwrapName(table);
      Table tableFromRedis = null;

      for(String element : this.cache.getDataBase().getTableNamelistKey(sch.getName())) {
         if (isSensitive) {
            if (table.equals(element)) {
               tableFromRedis = this.cache.getDataBase().getTableFromRedis(sch.getName(), element);
            }
         } else if (table.equalsIgnoreCase(element)) {
            tableFromRedis = this.cache.getDataBase().getTableFromRedis(sch.getName(), element);
         }
      }

      return tableFromRedis;
   }

   public View getViewFromRedis(Schema sch, String viewName, boolean isSensitive) {
      if (!StringUtils.isEmpty(viewName) && sch != null) {
         viewName = this.unwrapName(viewName);
         View viewFromRedis = null;

         for(String element : this.cache.getDataBase().getViewNamelistKey(sch.getName())) {
            if (isSensitive) {
               if (viewName.equals(element)) {
                  viewFromRedis = this.cache.getDataBase().getViewFromRedis(sch.getName(), element);
               }
            } else if (viewName.equalsIgnoreCase(element)) {
               viewFromRedis = this.cache.getDataBase().getViewFromRedis(sch.getName(), element);
            }
         }

         return viewFromRedis;
      } else {
         return null;
      }
   }

   public Schema getSchemaFromRedis(String schema, boolean isSensitive) {
      if (StringUtils.isEmpty(schema)) {
         return null;
      } else {
         schema = this.unwrapName(schema);

         for(String element : this.cache.getDataBase().getSchemaNamelistKey()) {
            if (isSensitive) {
               if (schema.equals(element)) {
                  Schema item = new Schema(schema);
                  item.setRealName(schema);
                  return item;
               }
            } else if (schema.equalsIgnoreCase(element)) {
               Schema item = new Schema(schema);
               item.setRealName(schema);
               return item;
            }
         }

         return null;
      }
   }

   public static class ColInfo {
      public String schema;
      public String table;
      public String column;

      public String unwrap(String placeholder) {
         StringBuilder sb = new StringBuilder();
         if (this.table != null && this.table.length() > 0) {
            sb.append(this.table.replaceAll(placeholder, ""));
            sb.append(".");
         }

         if (this.column != null && this.column.length() > 0) {
            sb.append(this.column.replaceAll(placeholder, ""));
         }

         return sb.toString();
      }

      public boolean isValid() {
         return this.schema != null && this.schema.length() > 0 && this.table != null && this.table.length() > 0 && this.column != null && this.column.length() > 0;
      }
   }
}
