/**
 * oracle语法解析的监听器，实现符号表
 */
import {OracleListenerBase} from "./oracleListenerBase";
import {SymbolTable} from "../../symbols/symbolTable";
import {Unit_statementContext, Select_statementContext} from "../../grammar/oracle/PlSqlParser";
import {HashMap} from "@nebtex/hashmaps";
import {ElementType, SymbolElement} from "../../symbols/symbolElement";
import {Select_list_elementsContext} from "../../grammar/oracle/PlSqlParser";
import {ExpressionsContext} from "../../grammar/oracle/PlSqlParser";
import {ExpressionContext} from "../../grammar/oracle/PlSqlParser";
import {Table_ref_auxContext} from "../../grammar/oracle/PlSqlParser";
import {Table_aliasContext, Table_ref_aux_internal_oneContext} from "../../grammar/oracle/PlSqlParser";

export class OracleListener extends OracleListenerBase{

    /**
     * 符号表
     */
    private symbolTable:SymbolTable;

    /**
     * 当前作用域
     */
    private currentLevel:string = "0";


    constructor(symbolTable: SymbolTable) {
        super();
        this.symbolTable = symbolTable;
    }

    /**
     * 进入了普通sql的顶级规则中，创建一个顶级作用域
     */

    enterUnit_statement: (ctx: Unit_statementContext) => void = (ctx: Unit_statementContext):void => {
        let table:HashMap<any, SymbolElement> = new HashMap<any, SymbolElement>();
        let level:string = this.symbolTable.insertTable(this.currentLevel, table);
        this.currentLevel = level;

    };

    /**
     * 退出顶级作用域
     */
    exitUnit_statement: (ctx: Unit_statementContext) => void = (ctx):void => {
        this.currentLevel = this.symbolTable.exitTable(this.currentLevel);
    };


    /***************************************开始select语句***************************************************/
    /**
     * 进入到select语句中
     */
    enterSelect_statement: (ctx: Select_statementContext) => void = (ctx: Select_statementContext): void => {
        let table:HashMap<any, SymbolElement> = new HashMap<any, SymbolElement>();
        let level:string = this.symbolTable.insertTable(this.currentLevel, table);
        this.currentLevel = level;
    };

    /**
     * 退出select语句
     * @param ctx
     */
    exitSelect_statement: (ctx: Select_statementContext) => void = (ctx: Select_statementContext): void => {
        this.currentLevel = this.symbolTable.exitTable(this.currentLevel);
    };


    /**
     * 进入到select语句中字段元素（可能一个，也肯定多个）
     * 思路：
     * 1.判断select_list_elements的子节点是不是expressions
     * 2.找到expressions子级节点为expression的节点
     * 3.expression节点此时表示了字段，写入到符号表中
     * @param ctx
     */
    enterSelect_list_elements: (ctx: Select_list_elementsContext) => void = (ctx: Select_list_elementsContext):void =>{

        for (let expressions of ctx.children){
            //1.判断select_list_elements的子节点是不是expressions，如果不是就返回
            if (expressions instanceof ExpressionsContext){
                for (let expression of expressions.children){
                    if (expression instanceof ExpressionContext){
                        let element = new SymbolElement();
                        element.startIndex = expression.start.startIndex;
                        element.stopIndex = expression.stop.stopIndex;
                        element.text = expression.text;
                        element.type = ElementType.COLUMN;
                        element.level =  this.currentLevel;

                        this.symbolTable.getTable(this.currentLevel).set(element.startIndex, element);
                    }
                }
            }
        }
    };


    /**
     * 解决select语句中table的定位
     * 思路：
     * 1.进入到table_ref_aux
     * 2.找到table_ref_aux_internal的table_ref_aux_internal_one，此处为真实的表名
     * 3.找到table_alias，如果有，则表示当前表有别名，设置别名。
     * 注意：当前仅支持table_ref_aux_internal_one
     * @param ctx
     */
    enterTable_ref_aux: (ctx: Table_ref_auxContext) => void = (ctx: Table_ref_auxContext):void  => {

        let element:SymbolElement;

        for (let children of ctx.children){
            if (children instanceof Table_ref_aux_internal_oneContext){
                element = new SymbolElement();
                element.startIndex = children.start.startIndex;
                element.stopIndex = children.stop.stopIndex;
                element.level = this.currentLevel;
                element.type = ElementType.TABLE;
                element.text = children.text;
            }

            if (children instanceof Table_aliasContext && element != undefined){
                element.alias = children.text;
            }

        }

        if (element != undefined){
            this.symbolTable.getTable(this.currentLevel).set(element.startIndex, element);
        }
        
    };

    














    /***************************************结束select语句***************************************************/

    /***************************************开始delete语句***************************************************/
    /***************************************结束select语句***************************************************/

    /***************************************开始update语句***************************************************/
    /***************************************结束update语句***************************************************/

    /***************************************开始insert语句***************************************************/
    /***************************************结束insert语句***************************************************/





}