
/* tslint:disable */
import { ExtHostContext, IExtHostContext, MainContext } from '@workbench-stack/extension-api/lib/protocol/server.protocol';
import { Observable, Subscription } from 'rxjs';
import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from '@vscode/monaco-editor/esm/vs/editor/browser/editorBrowser';
import { ITextModel } from '@vscode/monaco-editor/esm/vs/editor/common/model';
import { values } from '@vscode/monaco-editor/esm/vs/base/common/map';


namespace delta {

    export function ofSets<T>(before: Set<T> = new Set(), after: Set<T>): { removed: T[], added: T[] } {
        const removed: T[] = [];
        const added: T[] = [];
        before.forEach(element => {
            if (!after.has(element)) {
                removed.push(element);
            }
        });
        after.forEach(element => {
            if (!before.has(element)) {
                added.push(element);
            }
        });
        return { removed, added };
    }

    export function ofMaps<K, V>(before: Map<K, V> = new Map(), after: Map<K, V>): { removed: V[], added: V[] } {
        const removed: V[] = [];
        const added: V[] = [];
        before.forEach((value, index) => {
            if (!after.has(index)) {
                removed.push(value);
            }
        });
        after.forEach((value, index) => {
            if (!before.has(index)) {
                added.push(value);
            }
        });
        return { removed, added };
    }
}

export class TextEditorSnapshot {

    readonly id: string;

    constructor(
        readonly editor: IActiveCodeEditor,
    ) {
        this.id = `${editor.getId()},${editor.getModel().id}`;
    }
}


export class DocumentAndEditorStateDelta {

    readonly isEmpty: boolean;

    constructor(
        readonly removedDocuments: ITextModel[],
        readonly addedDocuments: ITextModel[],
        readonly removedEditors: TextEditorSnapshot[],
        readonly addedEditors: TextEditorSnapshot[],
        readonly oldActiveEditor: string | null | undefined,
        readonly newActiveEditor: string | null | undefined,
    ) {
        this.isEmpty = this.removedDocuments.length === 0
            && this.addedDocuments.length === 0
            && this.removedEditors.length === 0
            && this.addedEditors.length === 0
            && oldActiveEditor === newActiveEditor;
    }

    toString(): string {
        let ret = 'DocumentAndEditorStateDelta\n';
        ret += `\tRemoved Documents: [${this.removedDocuments.map(d => d.uri.toString(true)).join(', ')}]\n`;
        ret += `\tAdded Documents: [${this.addedDocuments.map(d => d.uri.toString(true)).join(', ')}]\n`;
        ret += `\tRemoved Editors: [${this.removedEditors.map(e => e.id).join(', ')}]\n`;
        ret += `\tAdded Editors: [${this.addedEditors.map(e => e.id).join(', ')}]\n`;
        ret += `\tNew Active Editor: ${this.newActiveEditor}\n`;
        return ret;
    }
}

export class DocumentAndEditorState {

	static compute(before: DocumentAndEditorState, after: DocumentAndEditorState): DocumentAndEditorStateDelta {
		if (!before) {
			return new DocumentAndEditorStateDelta(
				[], values(after.documents),
				[], values(after.textEditors),
				undefined, after.activeEditor
			);
		}
		const documentDelta = delta.ofSets(before.documents, after.documents);
		const editorDelta = delta.ofMaps(before.textEditors, after.textEditors);
		const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
		const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;

		return new DocumentAndEditorStateDelta(
			documentDelta.removed, documentDelta.added,
			editorDelta.removed, editorDelta.added,
			oldActiveEditor, newActiveEditor
		);
	}

	constructor(
		readonly documents: Set<ITextModel>,
		readonly textEditors: Map<string, TextEditorSnapshot>,
		readonly activeEditor: string | null | undefined,
	) {
		//
	}
}

const enum ActiveEditorOrder {
	Editor, Panel
}


