package util.sqlparse.visitor.hive.parser;

import bean.DataBase;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.stat.TableStat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import util.sqlparse.visitor.common.Context;
import util.sqlparse.visitor.common.bean.FieldInfo;
import util.sqlparse.visitor.common.bean.SQLResult;
import util.sqlparse.visitor.common.bean.TableInfo;
import util.sqlparse.visitor.common.bean.ValueInfo;
import util.sqlparse.visitor.common.memo.FieldMemo;
import util.sqlparse.visitor.common.memo.TableMemo;
import util.sqlparse.visitor.common.scope.Scope;
import util.sqlparse.visitor.mysql.SQLParser;
import util.sqlparse.visitor.mysql.visitor.CompoundVisitor;
import util.sqlparse.visitor.mysql.visitor.MySQLScopeDialector;

public class CompoundSQLStatementParser extends SQLStatementParser {
   public SQLResult parseStatement(SQLStatement statement, DataBase dataBase, String schema) {
      Context context = new Context();
      context.initialize(dataBase, schema, "mysql");
      Scope scope = new Scope();
      scope.dialector = new MySQLScopeDialector(scope);
      scope.context = context;
      CompoundVisitor scopeVisitor = new CompoundVisitor(scope);
      scopeVisitor.perform(Arrays.asList(statement));
      SQLResult result = this.collectResults(scope);
      result.sqlType = TableStat.Mode.Other;
      result.statement = statement;
      result.statementType = SQLParser.getStatementType(result.statement);
      return result;
   }

   private SQLResult collectResults(Scope scope) {
      SQLResult result = new SQLResult();
      DataBase db = scope.context.getDataBase();
      Map<String, TableInfo> tableMap = new HashMap();
      Map<String, FieldInfo> fieldMap = new HashMap();
      List<FieldInfo> moutputs = new ArrayList();
      List<ValueInfo> mvalues = new ArrayList();
      List<TableMemo> mtableMemos = new ArrayList();
      List<FieldMemo> moutputMemos = new ArrayList();
      List<FieldMemo> mfieldMemos = new ArrayList();

      for(SQLResult sr : scope.results) {
         if (sr != null) {
            this.collectTables(tableMap, sr);
            this.collectFields(fieldMap, sr, scope);
            this.collectOutputs(moutputs, sr);
            this.collectTableMemos(mtableMemos, sr);
            this.collectOutputMemos(moutputMemos, sr);
            this.collectFieldMemos(mfieldMemos, sr);
         }
      }

      result.tables = new ArrayList(tableMap.values());
      result.fields = new ArrayList(fieldMap.values());
      result.values = mvalues;
      result.tableMemos = mtableMemos;
      result.outputMemos = moutputMemos;
      result.fieldMemos = mfieldMemos;
      return result;
   }

   private void collectTables(Map<String, TableInfo> tableMap, SQLResult sr) {
      List<TableInfo> tables = sr.tables;
      if (tables != null) {
         for(TableInfo table : tables) {
            if (table != null) {
               String atomName = table.getAtomName();
               if (atomName != null) {
                  if (!tableMap.containsKey(atomName)) {
                     tableMap.put(atomName, table);
                  } else {
                     TableInfo t = (TableInfo)tableMap.get(atomName);
                     List<TableMemo> memos = table.getMemos();
                     if (memos != null) {
                        for(TableMemo memo : memos) {
                           t.addMemo(memo);
                        }
                     }
                  }
               }
            }
         }
      }

   }

   private void collectFields(Map<String, FieldInfo> fieldMap, SQLResult sr, Scope scope) {
      List<FieldInfo> fields = sr.fields;
      if (fields != null) {
         for(FieldInfo field : fields) {
            if (field != null) {
               String name = field.fullPathName(scope.dialector);
               if (scope.context.getDataBase().simpleCache.containsColumn(name) && name != null) {
                  if (!fieldMap.containsKey(name)) {
                     fieldMap.put(name, field);
                  } else {
                     FieldInfo t = (FieldInfo)fieldMap.get(name);
                     List<FieldMemo> memos = field.getMemos();
                     if (memos != null) {
                        for(FieldMemo memo : memos) {
                           t.addMemo(memo);
                        }
                     }
                  }
               }
            }
         }
      }

   }

   private void collectTableMemos(List<TableMemo> mtableMemos, SQLResult sr) {
      List<TableMemo> tableMemos = sr.tableMemos;
      if (tableMemos != null && tableMemos.size() > 0) {
         mtableMemos.addAll(tableMemos);
      }

   }

   private void collectOutputs(List<FieldInfo> moutputs, SQLResult sr) {
      List<FieldInfo> outputs = sr.outputs;
      if (outputs != null && outputs.size() > 0) {
         moutputs.addAll(outputs);
      }

   }

   private void collectOutputMemos(List<FieldMemo> moutputMemos, SQLResult sr) {
      List<FieldMemo> outputMemos = sr.outputMemos;
      if (outputMemos != null && outputMemos.size() > 0) {
         moutputMemos.addAll(outputMemos);
      }

   }

   private void collectFieldMemos(List<FieldMemo> mfieldMemos, SQLResult sr) {
      List<FieldMemo> fieldMemos = sr.fieldMemos;
      if (fieldMemos != null && fieldMemos.size() > 0) {
         mfieldMemos.addAll(fieldMemos);
      }

   }
}
