package util.sqlparse.visitor.oracle.visitor;


import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.statement.*;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectJoin;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.chenyang.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.chenyang.druid.sql.dialect.oracle.visitor.DefaultOracleASTVisitor;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import com.chenyang.druid.stat.TableStat;
import util.sqlparse.visitor.common.scope.Scope;

public class PassViewVisitor extends DefaultOracleASTVisitor {
    protected Scope scope;

    protected String schema;

    public PassViewVisitor(Scope scope, String schema) {
        this.scope = scope;
        this.schema = schema;
    }

    public boolean visit(OracleSelectJoin from) {
        visit((SQLJoinTableSource)from);
        return false;
    }

    public boolean visit(SQLJoinTableSource from) {
        SQLJoinTableSource jts = from;
        if (jts.getLeft() instanceof SQLExprTableSource || jts.getLeft() instanceof OracleSelectTableReference) {
            SQLSelect subSelect = getViewTableSource(jts.getLeft());
            if (subSelect != null)
                subSelect.accept((SQLASTVisitor)this);
        } else {
            jts.getLeft().accept((SQLASTVisitor)this);
        }
        if (jts.getRight() instanceof SQLExprTableSource || jts.getRight() instanceof OracleSelectTableReference) {
            SQLSelect subSelect = getViewTableSource(jts.getRight());
            if (subSelect != null)
                subSelect.accept((SQLASTVisitor)this);
        } else {
            jts.getRight().accept((SQLASTVisitor)this);
        }
        return false;
    }

    public boolean visit(OracleSelectTableReference from) {
        if (from instanceof SQLExprTableSource || from instanceof OracleSelectTableReference) {
            SQLSelect subSelect = getViewTableSource((SQLTableSource)from);
            if (subSelect != null) {
                subSelect.accept((SQLASTVisitor)this);
            } else {
                String selfSchema = from.getSchema();
                if (null == selfSchema || selfSchema.length() == 0)
                    from.setSchema(this.schema);
            }
        }
        return false;
    }

    private SQLSelect getViewTableSource(SQLTableSource ts) {
        SQLExprTableSource e = (SQLExprTableSource)ts;
        String name = e.getTableName();
        if (name == null)
            return null;
        String schema = (e.getSchema() == null) ? this.scope.getDefaultSchema() : e.getSchema();
        SQLSelect view = this.scope.context.getView(schema.toLowerCase(), name.toLowerCase());
        if (view != null &&
                this.scope.context.sqlType == TableStat.Mode.Select) {
            SQLSubqueryTableSource subQuery = new SQLSubqueryTableSource();
            String alias = (e.getAlias() == null) ? e.getTableName() : e.getAlias();
            subQuery.setAlias(alias);
            subQuery.setSelect(view.clone());
            SQLObject parent = ts.getParent();
            if (parent instanceof OracleSelectQueryBlock) {
                OracleSelectQueryBlock block = (OracleSelectQueryBlock)parent;
                block.setFrom((SQLTableSource)subQuery);
                subQuery.setParent(parent);
            } else if (parent instanceof OracleSelectJoin) {
                OracleSelectJoin join = (OracleSelectJoin)parent;
                if (join.getLeft() == ts) {
                    join.setLeft((SQLTableSource)subQuery);
                } else {
                    join.setRight((SQLTableSource)subQuery);
                }
            }
            return subQuery.getSelect();
        }
        return null;
    }
}

