package com.alibaba.qlexpress4.exception;

import com.alibaba.qlexpress4.exception.lsp.Diagnostic;
import com.alibaba.qlexpress4.exception.lsp.Position;
import com.alibaba.qlexpress4.exception.lsp.Range;

public class QLException extends RuntimeException {
    
    private final Diagnostic diagnostic;
    
    protected QLException(String message, Diagnostic diagnostic) {
        super(message);
        this.diagnostic = diagnostic;
    }
    
    public Diagnostic getDiagnostic() {
        return diagnostic;
    }
    
    public int getPos() {
        return diagnostic.getPos();
    }
    
    public String getReason() {
        return diagnostic.getMessage();
    }
    
    /**
     * @return line no based 1
     */
    public int getLineNo() {
        return diagnostic.getRange().getStart().getLine() + 1;
    }
    
    /**
     * @return col no based 1
     */
    public int getColNo() {
        return diagnostic.getRange().getStart().getCharacter() + 1;
    }
    
    public String getErrLexeme() {
        return diagnostic.getLexeme();
    }
    
    public String getErrorCode() {
        return diagnostic.getCode();
    }
    
    public static QLSyntaxException reportScannerErr(String script, int tokenStartPos, int line, int col, String lexeme,
        String errorCode, String reason) {
        ExMessageUtil.ExMessage exMessage =
            ExMessageUtil.format(script, tokenStartPos, line, col, lexeme, errorCode, reason);
        Diagnostic diagnostic =
            toDiagnostic(tokenStartPos, line, col, lexeme, errorCode, reason, exMessage.getSnippet());
        return new QLSyntaxException(exMessage.getMessage(), diagnostic);
    }
    
    public static QLRuntimeException reportRuntimeErrWithAttach(String script, int tokenStartPos, int line, int col,
        String lexeme, String errorCode, String reason, Object catchObj) {
        ExMessageUtil.ExMessage exMessage =
            ExMessageUtil.format(script, tokenStartPos, line, col, lexeme, errorCode, reason);
        Diagnostic diagnostic =
            toDiagnostic(tokenStartPos, line, col, lexeme, errorCode, reason, exMessage.getSnippet());
        return errorCode.equals(QLErrorCodes.SCRIPT_TIME_OUT.name())
            ? new QLTimeoutException(catchObj, exMessage.getMessage(), diagnostic)
            : new QLRuntimeException(catchObj, exMessage.getMessage(), diagnostic);
    }
    
    private static Diagnostic toDiagnostic(int startPos, int line, int col, String lexeme, String errorCode,
        String reason, String snippet) {
        int zeroBasedLine = line - 1;
        int zeroBasedCol = col - 1;
        Position start = new Position(zeroBasedLine, zeroBasedCol);
        Position end = new Position(zeroBasedLine, zeroBasedCol + lexeme.length());
        Range range = new Range(start, end);
        return new Diagnostic(startPos, range, lexeme, errorCode, reason, snippet);
    }
}
