import * as vscode from 'vscode';

/**
 * Class for displaying the result of a duplicate code search
 */
export class DuplicateCodeView{
    private _decor:vscode.TextEditorDecorationType;
    private _panel:any;

    /** Last saved search data */
    private _savedDuplicates:any = undefined;

    constructor(){
        this._decor=vscode.window.createTextEditorDecorationType(
                    {backgroundColor: vscode.workspace.getConfiguration('RefactorErl').get('DuplicateCodeColor')}
                );
        vscode.workspace.onDidChangeConfiguration(() => { 
            this._decor=vscode.window.createTextEditorDecorationType(
                    {backgroundColor: vscode.workspace.getConfiguration('RefactorErl').get('DuplicateCodeColor')}
                );
        });
    }

    /**
     * Updates the stored data with the new result
     * @param NewList Received result
     */
    public updateCodeList(NewList:any):void{
        if(this._panel !== undefined){ this._panel.dispose(); }
        this._savedDuplicates = NewList;
        this.Display();
    }

    /**
     * Displays the stored search result
     */
    public Display():void{
        if(this._savedDuplicates === undefined){
            vscode.window.showErrorMessage("There are no saved duplicate codes. Run a search first.");
            return;
        }
        this._panel = vscode.window.createWebviewPanel(
                        "dupcodes", "Duplicate Search Results",
                        vscode.ViewColumn.Beside, {enableScripts:true}
                    );
        this._panel.webview.html = CreateDupCode_HTML(this._savedDuplicates);
        this._panel.webview.onDidReceiveMessage( (message:any) => {
                this.ShowSelected(this._savedDuplicates[parseInt(message.index)].PathRange); 
            });
    }

    /**
     * Highlights the selected group of duplicates
     * @param SelectedGroup Group of duplicates selected by the user
     */
    private async ShowSelected(SelectedGroup:any):Promise<void>{
        let ProcessedPaths:string[] = [];
        for(let Elem of SelectedGroup){
            if(ProcessedPaths.indexOf(Elem.Path) === -1){
                ProcessedPaths.push(Elem.Path);
                let Ranges:vscode.Range[] = [];
                for(let item of SelectedGroup.filter((arg:any) => { return arg.Path === Elem.Path; })){
                    Ranges = Ranges.concat(item.Range);
                }
                await SetDecor(Elem.Path, Ranges, this._decor);
            }
        }
        this._panel.dispose();
    }
}

/**
 * Highlights the received range
 * @param Path File to open
 * @param Ranges range of texts to highlight
 * @param Decor Decoration to apply to the ranges
 */
async function SetDecor(Path:string, Ranges:vscode.Range[],
                        Decor:vscode.TextEditorDecorationType):Promise<void>{
    let Doc = await vscode.workspace.openTextDocument(vscode.Uri.file(Path));
    await vscode.window.showTextDocument(Doc, vscode.ViewColumn.Beside);
    let editor = vscode.window.activeTextEditor;
    if(editor !== undefined){
        editor.setDecorations(Decor, Ranges);
    }
}

/**
 * Creates the HTML page string for the result page
 * @param Results Results used for the page
 * @returns String HTML string of the created page
 */
function CreateDupCode_HTML(Results:any):string{
    let script = `<script>
    const vscode = acquireVsCodeApi();
    for (const link of document.querySelectorAll('#dup')){
        link.addEventListener('click', () => {
            vscode.postMessage({index: link.getAttribute('href')});
        });
    }</script>`;

    let body = `<p>Duplicate Clone name: ${Results[0].CloneName}</p><br/>`;
    for(let Elem of Results){
        body += `<a id="dup", href=${Results.indexOf(Elem)}>Group number: ${Elem.Group_No}</a><br/>`;
    }

    return `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Duplicate Search Results</title></head><body>`+body+script+`</body></html>`;
}