package com.chenyang.druid.sql.dialect.oracle.ast.clause;

import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLExprImpl;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLOrderBy;
import com.chenyang.druid.sql.ast.SQLReplaceable;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.dialect.oracle.ast.OracleSQLObjectImpl;
import com.chenyang.druid.sql.dialect.oracle.ast.expr.OracleExpr;
import com.chenyang.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.List;

public class ModelClause extends OracleSQLObjectImpl {
   private final List<CellReferenceOption> cellReferenceOptions = new ArrayList();
   private ReturnRowsClause returnRowsClause;
   private final List<ReferenceModelClause> referenceModelClauses = new ArrayList();
   private MainModelClause mainModel;

   public void accept0(OracleASTVisitor visitor) {
      if (visitor.visit(this)) {
         this.acceptChild(visitor, this.returnRowsClause);
         this.acceptChild(visitor, this.referenceModelClauses);
         this.acceptChild(visitor, this.mainModel);
      }

      visitor.endVisit(this);
   }

   public MainModelClause getMainModel() {
      return this.mainModel;
   }

   public void setMainModel(MainModelClause mainModel) {
      this.mainModel = mainModel;
   }

   public ReturnRowsClause getReturnRowsClause() {
      return this.returnRowsClause;
   }

   public void setReturnRowsClause(ReturnRowsClause returnRowsClause) {
      this.returnRowsClause = returnRowsClause;
   }

   public List<ReferenceModelClause> getReferenceModelClauses() {
      return this.referenceModelClauses;
   }

   public List<CellReferenceOption> getCellReferenceOptions() {
      return this.cellReferenceOptions;
   }

   public ModelClause clone() {
      throw new UnsupportedOperationException();
   }

   public static enum CellReferenceOption {
      IgnoreNav("IGNORE NAV"),
      KeepNav("KEEP NAV"),
      UniqueDimension("UNIQUE DIMENSION"),
      UniqueSingleReference("UNIQUE SINGLE REFERENCE");

      public final String name;

      private CellReferenceOption() {
         this(null);
      }

      private CellReferenceOption(String name) {
         this.name = name;
      }

      public String toString() {
         return this.name;
      }
   }

   public static class ReturnRowsClause extends OracleSQLObjectImpl {
      private boolean all = false;

      public boolean isAll() {
         return this.all;
      }

      public void setAll(boolean all) {
         this.all = all;
      }

      public void accept0(OracleASTVisitor visitor) {
         visitor.visit(this);
         visitor.endVisit(this);
      }
   }

   public static class ReferenceModelClause extends OracleSQLObjectImpl {
      private SQLExpr name;
      private SQLSelect subQuery;
      private final List<CellReferenceOption> cellReferenceOptions = new ArrayList();

      public List<CellReferenceOption> getCellReferenceOptions() {
         return this.cellReferenceOptions;
      }

      public SQLExpr getName() {
         return this.name;
      }

      public void setName(SQLExpr name) {
         this.name = name;
      }

      public SQLSelect getSubQuery() {
         return this.subQuery;
      }

      public void setSubQuery(SQLSelect subQuery) {
         this.subQuery = subQuery;
      }

      public void accept0(OracleASTVisitor visitor) {
      }
   }

   public static class ModelColumnClause extends OracleSQLObjectImpl {
      private QueryPartitionClause queryPartitionClause;
      private String alias;
      private final List<ModelColumn> dimensionByColumns = new ArrayList();
      private final List<ModelColumn> measuresColumns = new ArrayList();

      public List<ModelColumn> getDimensionByColumns() {
         return this.dimensionByColumns;
      }

      public List<ModelColumn> getMeasuresColumns() {
         return this.measuresColumns;
      }

      public QueryPartitionClause getQueryPartitionClause() {
         return this.queryPartitionClause;
      }

      public void setQueryPartitionClause(QueryPartitionClause queryPartitionClause) {
         this.queryPartitionClause = queryPartitionClause;
      }

      public String getAlias() {
         return this.alias;
      }

      public void setAlias(String alias) {
         this.alias = alias;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.queryPartitionClause);
            this.acceptChild(visitor, this.dimensionByColumns);
            this.acceptChild(visitor, this.measuresColumns);
         }

         visitor.endVisit(this);
      }
   }

   public static class ModelColumn extends OracleSQLObjectImpl {
      private SQLExpr expr;
      private String alias;

      public SQLExpr getExpr() {
         return this.expr;
      }

      public void setExpr(SQLExpr expr) {
         this.expr = expr;
      }

      public String getAlias() {
         return this.alias;
      }

      public void setAlias(String alias) {
         this.alias = alias;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.expr);
         }

         visitor.endVisit(this);
      }
   }

   public static class QueryPartitionClause extends OracleSQLObjectImpl {
      private List<SQLExpr> exprList = new ArrayList();

      public List<SQLExpr> getExprList() {
         return this.exprList;
      }

      public void setExprList(List<SQLExpr> exprList) {
         this.exprList = exprList;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.exprList);
         }

      }
   }

   public static class MainModelClause extends OracleSQLObjectImpl {
      private SQLExpr mainModelName;
      private ModelColumnClause modelColumnClause;
      private final List<CellReferenceOption> cellReferenceOptions = new ArrayList();
      private ModelRulesClause modelRulesClause;

      public ModelRulesClause getModelRulesClause() {
         return this.modelRulesClause;
      }

      public void setModelRulesClause(ModelRulesClause modelRulesClause) {
         this.modelRulesClause = modelRulesClause;
      }

      public List<CellReferenceOption> getCellReferenceOptions() {
         return this.cellReferenceOptions;
      }

      public ModelColumnClause getModelColumnClause() {
         return this.modelColumnClause;
      }

      public void setModelColumnClause(ModelColumnClause modelColumnClause) {
         this.modelColumnClause = modelColumnClause;
      }

      public SQLExpr getMainModelName() {
         return this.mainModelName;
      }

      public void setMainModelName(SQLExpr mainModelName) {
         this.mainModelName = mainModelName;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.mainModelName);
            this.acceptChild(visitor, this.modelColumnClause);
            this.acceptChild(visitor, this.modelRulesClause);
         }

         visitor.endVisit(this);
      }
   }

   public static class ModelRulesClause extends OracleSQLObjectImpl {
      private final List<ModelRuleOption> options = new ArrayList();
      private SQLExpr iterate;
      private SQLExpr until;
      private final List<CellAssignmentItem> cellAssignmentItems = new ArrayList();

      public SQLExpr getUntil() {
         return this.until;
      }

      public void setUntil(SQLExpr until) {
         this.until = until;
      }

      public SQLExpr getIterate() {
         return this.iterate;
      }

      public void setIterate(SQLExpr iterate) {
         this.iterate = iterate;
      }

      public List<ModelRuleOption> getOptions() {
         return this.options;
      }

      public List<CellAssignmentItem> getCellAssignmentItems() {
         return this.cellAssignmentItems;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.iterate);
            this.acceptChild(visitor, this.until);
            this.acceptChild(visitor, this.cellAssignmentItems);
         }

         visitor.endVisit(this);
      }
   }

   public static enum ModelRuleOption {
      UPSERT("UPSERT"),
      UPDATE("UPDATE"),
      AUTOMATIC_ORDER("AUTOMATIC ORDER"),
      SEQUENTIAL_ORDER("SEQUENTIAL ORDER");

      public final String name;

      private ModelRuleOption(String name) {
         this.name = name;
      }

      public String toString() {
         return this.name;
      }
   }

   public static class CellAssignmentItem extends OracleSQLObjectImpl {
      private ModelRuleOption option;
      private CellAssignment cellAssignment;
      private SQLOrderBy orderBy;
      private SQLExpr expr;

      public ModelRuleOption getOption() {
         return this.option;
      }

      public void setOption(ModelRuleOption option) {
         this.option = option;
      }

      public CellAssignment getCellAssignment() {
         return this.cellAssignment;
      }

      public void setCellAssignment(CellAssignment cellAssignment) {
         this.cellAssignment = cellAssignment;
      }

      public SQLOrderBy getOrderBy() {
         return this.orderBy;
      }

      public void setOrderBy(SQLOrderBy orderBy) {
         this.orderBy = orderBy;
      }

      public SQLExpr getExpr() {
         return this.expr;
      }

      public void setExpr(SQLExpr expr) {
         this.expr = expr;
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.cellAssignment);
            this.acceptChild(visitor, this.orderBy);
            this.acceptChild(visitor, this.expr);
         }

         visitor.endVisit(this);
      }
   }

   public static class CellAssignment extends SQLExprImpl implements OracleExpr, SQLReplaceable {
      private SQLExpr measureColumn;
      private final List<SQLExpr> conditions = new ArrayList();

      public List<SQLExpr> getConditions() {
         return this.conditions;
      }

      public SQLExpr getMeasureColumn() {
         return this.measureColumn;
      }

      public void setMeasureColumn(SQLExpr e) {
         if (e != null) {
            e.setParent(this);
         }

         this.measureColumn = e;
      }

      public boolean replace(SQLExpr expr, SQLExpr target) {
         if (this.measureColumn == expr) {
            this.setMeasureColumn(target);
            return true;
         } else {
            for(int i = 0; i < this.conditions.size(); ++i) {
               if (this.conditions.get(i) == expr) {
                  target.setParent(this);
                  this.conditions.set(i, target);
                  return true;
               }
            }

            return false;
         }
      }

      public void accept0(OracleASTVisitor visitor) {
         if (visitor.visit(this)) {
            this.acceptChild(visitor, this.measureColumn);
            this.acceptChild(visitor, this.conditions);
         }

         visitor.endVisit(this);
      }

      public boolean equals(Object o) {
         if (this == o) {
            return true;
         } else if (o != null && this.getClass() == o.getClass()) {
            CellAssignment that = (CellAssignment)o;
            if (this.measureColumn != null) {
               if (!this.measureColumn.equals(that.measureColumn)) {
                  return false;
               }
            } else if (that.measureColumn != null) {
               return false;
            }

            return this.conditions.equals(that.conditions);
         } else {
            return false;
         }
      }

      public int hashCode() {
         int result = this.measureColumn != null ? this.measureColumn.hashCode() : 0;
         result = 31 * result + this.conditions.hashCode();
         return result;
      }

      protected void accept0(SQLASTVisitor visitor) {
         this.accept0((OracleASTVisitor)visitor);
      }

      public SQLExpr clone() {
         CellAssignment x = new CellAssignment();
         if (this.measureColumn != null) {
            x.setMeasureColumn(this.measureColumn.clone());
         }

         return null;
      }

      public List<SQLObject> getChildren() {
         List children = new ArrayList();
         children.add(this.measureColumn);
         children.addAll(this.conditions);
         return children;
      }
   }
}
