import * as vscode from 'vscode';

/**
 * Class for processing & displaying the result of a semantic query
 */
export class SemanticQueryView{
    /** Last SQ result stored */
    private _lastResults:any=undefined;
    private _panel:any;

    /**
     * Updates the stored data with the new result
     * @param NewData Result of the latest semantic query
     */
    public updateResult(NewData:any):void{
        if(this._panel !== undefined){ this._panel.dispose(); }
        this._lastResults = NewData;
        this.ShowLastResult();
    }

    /** Displays the stored query result */
    public ShowLastResult():void{
        if(this._lastResults === undefined){
            vscode.window.showErrorMessage("There are no saved Query results.");
            return;
        }
        this._panel = vscode.window.createWebviewPanel(
                        "semanticquery", "Semantic Query Results",
                        vscode.ViewColumn.Beside, {enableScripts:true}
                    );
        this._panel.webview.html = CreateSQ_HTML(this._lastResults);
        this._panel.webview.onDidReceiveMessage( (message:any) => {
            SetEditorFocus(this._lastResults[parseInt(message.index)][0]);
        });
    }
}

/**
 * Creates a HTML page for the received results
 * @param Results SQ data received
 * @returns String of the HTML to display
 */
function CreateSQ_HTML(Results:any):string{
    let script = `<script>
    const vscode = acquireVsCodeApi();
    for (const link of document.querySelectorAll('#res')){
        link.addEventListener('click', () => {
            vscode.postMessage({index: link.getAttribute('href')});
        });
    }</script>`;

    let body = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Semantic Query Results</title></head><body>`;

    for(let Elem of Results){
        body += `<a id="res", href=${Results.indexOf(Elem)}>${Elem[1]}</a><br/>`;
    }
    return body+script+`</body></html>`;
}

/**
 * Changes the focus of the editor if the user selects a result
 * @param NewFocusData Array which contains the data of the new focus
 */
export async function SetEditorFocus(NewFocusData:any):Promise<void>{
    let Doc = await vscode.workspace.openTextDocument(vscode.Uri.file(NewFocusData[0]));
    let Range = Doc.validateRange(AbsPosToRange(Doc, parseInt(NewFocusData[1]), parseInt(NewFocusData[2])));
    vscode.window.showTextDocument(Doc, {selection:Range});
}

/**
 * Converts 2 absolute positions into vscode.Range data type
 * @param doc Document of the positions
 * @param AbsPos1 Starting position
 * @param AbsPos2 Ending positions
 * @returns a vscode.Range data type
 */
function AbsPosToRange(doc:vscode.TextDocument, AbsPos1:number, AbsPos2:number):vscode.Range{
    if(doc.eol === 2){
        return new vscode.Range(doc.positionAt(AbsPos1+doc.positionAt(AbsPos1).line+1),
                                doc.positionAt(AbsPos2+doc.positionAt(AbsPos2).line+1));
    }
    return new vscode.Range(doc.positionAt(AbsPos1), doc.positionAt(AbsPos2));
}