import { Base64 } from "../util";
import { DialogProxyTools } from "./DialogProxyTools";
/**
 *
 */
export class DialogVisitor {
    constructor(value) {
        if (!value) {
            throw new Error('DialogVisitor -- null value exception');
        }
        if (typeof value === 'string') {
            this._enclosedJsonObject = JSON.parse(value);
        }
        else {
            this._enclosedJsonObject = value;
        }
        if (!DialogProxyTools.isDialogModel(this._enclosedJsonObject)) {
            throw new Error("Object passed to DialogVisitor is not a Dialog");
        }
    }
    // --- State Management Helpers --- //
    static propagateTenantIdAndSessionId(dialog, tenantId, sessionId) {
        (new DialogVisitor(dialog)).propagateTenantIdAndSessionId(tenantId, sessionId);
    }
    static visitId(dialog) {
        return (new DialogVisitor(dialog)).visitId();
    }
    static visitAndSetId(dialog, id) {
        (new DialogVisitor(dialog)).visitAndSetId(id);
    }
    // --- State Import/Export --- //
    copyAsJsonObject() {
        return JSON.parse(this.copyAsJsonString());
    }
    copyAsJsonString() {
        return JSON.stringify(this.enclosedJsonObject());
    }
    enclosedJsonObject() {
        return this._enclosedJsonObject;
    }
    // --- State Management --- //
    /**
     * The record id targeted by the root dialog (usually a Form) will be used to help derive new dialog ids for the
     * root and all of its children. The derived dialog id is a concatenation of the dialogName with a '@' and the
     * root record id.
     */
    deriveDialogIdsFromDialogNameAndRecordId() {
        let derivedDialogId = this.enclosedJsonObject()['dialogName'];
        if (!derivedDialogId) {
            throw new Error("Cannot derive dialog ids -- dialog name not found");
        }
        let rootRecordId = null;
        const referringObject = this.visitReferringObject();
        if (DialogProxyTools.isReferringDialogModel(referringObject)) {
            rootRecordId = this.visitRecordId();
            // TODO: Fix the error in Dialog Service that returns null record ids as a string literal of "null"
            if (rootRecordId && rootRecordId !== 'null') {
                const recordIdEncoded = Base64.encodeUrlSafeString(rootRecordId);
                derivedDialogId = `${derivedDialogId}@${recordIdEncoded}`;
            }
        }
        this.visitAndSetId(derivedDialogId);
        if (this.enclosedJsonObject()['children']) {
            for (const c of this.enclosedJsonObject()['children']) {
                const dialogVisitor = new DialogVisitor(c);
                dialogVisitor.deriveDialogIdsFromDialogName(rootRecordId);
            }
        }
    }
    /**
     * Traverse this dialog and its children and derive their dailog ids by concatenating each dialog's
     * dialogName with a '$' and the given suffix. Dialog ids ending withs a suffix are synthetic. Its possible
     * that a dialog id may have a suffix and a specific record id. In this case the dialog id will contain
     * a '$' and an '@' so that each field can be parsed separately.
     *
     * @param {string} suffix
     */
    deriveDialogIdsFromDialogNameAndSuffix(suffix) {
        let derivedDialogId = this.enclosedJsonObject()['dialogName'];
        if (!derivedDialogId) {
            throw new Error("Cannot propagate dialog ids -- dialog name not found");
        }
        if (suffix) {
            derivedDialogId = derivedDialogId + '$' + suffix;
        }
        this.visitAndSetId(derivedDialogId);
        if (this.enclosedJsonObject()['children']) {
            for (const c of this.enclosedJsonObject()['children']) {
                const dialogVisitor = new DialogVisitor(c);
                dialogVisitor.deriveDialogIdsFromDialogNameAndSuffix(suffix);
            }
        }
    }
    propagateTenantIdAndSessionId(tenantId, sessionId) {
        this.enclosedJsonObject()['tenantId'] = tenantId;
        this.enclosedJsonObject()['sessionId'] = sessionId;
        if (this.enclosedJsonObject()['children']) {
            for (const c of this.enclosedJsonObject()['children']) {
                const dialogVisitor = new DialogVisitor(c);
                dialogVisitor.propagateTenantIdAndSessionId(tenantId, sessionId);
            }
        }
    }
    visitDescription() {
        return this.enclosedJsonObject().description;
    }
    visitAndSetDescription(description) {
        this.enclosedJsonObject().description = description;
    }
    visitDialogName() {
        return this.enclosedJsonObject().dialogName;
    }
    visitId() {
        return this.enclosedJsonObject().id;
    }
    visitAndSetId(id) {
        this.enclosedJsonObject().id = id;
    }
    visitAndSetRootDialogId(rootDialogId) {
        this.enclosedJsonObject().rootDialogId = rootDialogId;
    }
    visitChildAt(index) {
        return new DialogVisitor(this.enclosedJsonObject().children[index]);
    }
    visitChildAtName(name) {
        if (this.enclosedJsonObject()['children']) {
            for (const c of this.enclosedJsonObject()['children']) {
                const dialogVisitor = new DialogVisitor(c);
                if (dialogVisitor.visitDialogName() && dialogVisitor.visitDialogName() === name) {
                    return dialogVisitor;
                }
                const childDialogVisitor = dialogVisitor.visitChildAtName(name);
                if (childDialogVisitor) {
                    return childDialogVisitor;
                }
            }
        }
        return null;
    }
    visitChildAtNameAndSetId(name, id) {
        const childDialogVisitor = this.visitChildAtName(name);
        if (childDialogVisitor) {
            childDialogVisitor.visitAndSetId(id);
            return true;
        }
        return false;
    }
    visitRecordId() {
        return this.enclosedJsonObject().recordId;
    }
    visitAndSetRecordId(recordId) {
        this.enclosedJsonObject().recordId = recordId;
    }
    visitReferringObject() {
        return this.enclosedJsonObject().referringObject;
    }
    visitAndSetReferringDialogId(dialogId) {
        this.visitReferringObject()['dialogId'] = dialogId;
    }
    deriveDialogIdsFromDialogName(rootRecordId) {
        let dialogName = this.enclosedJsonObject()['dialogName'];
        if (!dialogName) {
            throw new Error("Cannot propagate dialog name -- dialog name not found");
        }
        // TODO: Fix the error in Dialog Service that returns null record ids as a string literal of "null"
        if (rootRecordId && rootRecordId !== 'null') {
            const recordIdEncoded = Base64.encodeUrlSafeString(rootRecordId);
            dialogName = `${dialogName}@${recordIdEncoded}`;
        }
        if (rootRecordId) {
        }
        this.visitAndSetId(dialogName);
        if (this.enclosedJsonObject()['children']) {
            for (const c of this.enclosedJsonObject()['children']) {
                const dialogVisitor = new DialogVisitor(c);
                dialogVisitor.deriveDialogIdsFromDialogName(rootRecordId);
            }
        }
    }
}
