package com.alibaba.druid.sql.dialect.clickhouse.visitor;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLStructDataType;
import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.alibaba.druid.sql.dialect.clickhouse.ast.ClickhouseCreateTableStatement;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import java.util.List;

public class ClickhouseOutputVisitor extends SQLASTOutputVisitor implements ClickhouseVisitor {
   public ClickhouseOutputVisitor(Appendable appender) {
      super(appender);
   }

   public ClickhouseOutputVisitor(Appendable appender, DbType dbType) {
      super(appender, dbType);
   }

   public ClickhouseOutputVisitor(Appendable appender, boolean parameterized) {
      super(appender, parameterized);
   }

   public boolean visit(SQLWithSubqueryClause.Entry x) {
      if (x.getExpr() != null) {
         x.getExpr().accept(this);
      } else if (x.getSubQuery() != null) {
         this.print('(');
         this.println();
         SQLSelect query = x.getSubQuery();
         if (query != null) {
            query.accept(this);
         } else {
            x.getReturningStatement().accept(this);
         }

         this.println();
         this.print(')');
      }

      this.print(' ');
      this.print0(this.ucase ? "AS " : "as ");
      this.print0(x.getAlias());
      return false;
   }

   public boolean visit(SQLStructDataType x) {
      this.print0(this.ucase ? "NESTED (" : "nested (");
      this.incrementIndent();
      this.println();
      this.printlnAndAccept(x.getFields(), ",");
      this.decrementIndent();
      this.println();
      this.print(')');
      return false;
   }

   public boolean visit(SQLStructDataType.Field x) {
      SQLName name = x.getName();
      if (name != null) {
         name.accept(this);
      }

      SQLDataType dataType = x.getDataType();
      if (dataType != null) {
         this.print(' ');
         dataType.accept(this);
      }

      return false;
   }

   public boolean visit(ClickhouseCreateTableStatement x) {
      super.visit((SQLCreateTableStatement)x);
      SQLExpr partitionBy = x.getPartitionBy();
      if (partitionBy != null) {
         this.println();
         this.print0(this.ucase ? "PARTITION BY " : "partition by ");
         partitionBy.accept(this);
      }

      SQLOrderBy orderBy = x.getOrderBy();
      if (orderBy != null) {
         this.println();
         orderBy.accept(this);
      }

      SQLExpr sampleBy = x.getSampleBy();
      if (sampleBy != null) {
         this.println();
         this.print0(this.ucase ? "SAMPLE BY " : "sample by ");
         sampleBy.accept(this);
      }

      List<SQLAssignItem> settings = x.getSettings();
      if (!settings.isEmpty()) {
         this.println();
         this.print0(this.ucase ? "SETTINGS " : "settings ");
         this.printAndAccept(settings, ", ");
      }

      return false;
   }

   public void endVisit(ClickhouseCreateTableStatement x) {
   }
}
