var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { SdaDialogDelegate } from "../ppm/SdaDialogDelegate";
import { DialogProxyTools } from './DialogProxyTools';
import { DialogRequest } from "./DialogRequest";
import { ValueIterator } from "./ValueIterator";
export class DialogProxy {
    constructor() {
        this._lastActivity = new Date();
        this._initialized = false;
        this._initializedPr = new Promise((resolve, reject) => {
            this._initializedResolveFn = resolve;
            this._initializedRejectFn = reject;
        });
        this._dialogDelegateChain = [new SdaDialogDelegate()];
    }
    clientListener() {
        return this._clientListener;
    }
    // TODO: Shouldn't CvLocale either be a property of the Client or the Listener, not an extra parameter?
    addClientListener(clientListener, locale) {
        this._clientListener = clientListener;
        this._locale = locale;
    }
    removeClientListener(clientListener) {
        this._clientListener = null;
    }
    isAnyUserInBriefcaseMode(tenantId) {
        if (this._dialogDelegateChain && this._dialogDelegateChain.length > 0) {
            return this._dialogDelegateChain[0].isAnyUserInBriefcaseMode(tenantId);
        }
        else {
            return Promise.resolve(false);
        }
    }
    isUserInBriefcaseMode(userInfo) {
        if (this._dialogDelegateChain && this._dialogDelegateChain.length > 0) {
            return this._dialogDelegateChain[0].isUserInBriefcaseMode(userInfo);
        }
        else {
            return Promise.resolve(false);
        }
    }
    get lastActivity() {
        return this._lastActivity;
    }
    getBlob(baseUrl, resourcePath) {
        const dialogRequest = DialogRequest.createFromGetRequest(baseUrl, resourcePath, null);
        return this.processRequestAndResponse('getBlob', 'handleGetBlobResponse', [dialogRequest]);
    }
    getText(baseUrl, resourcePath) {
        const dialogRequest = DialogRequest.createFromGetRequest(baseUrl, resourcePath, null);
        return this.processRequestAndResponse('getText', 'handleGetTextResponse', [dialogRequest]);
    }
    openStream(baseUrl, resourcePath) {
        const dialogRequest = DialogRequest.createFromGetRequest(baseUrl, resourcePath, null);
        return this.processRequestAndResponse('openStream', 'handleOpenStreamResponse', [dialogRequest]);
    }
    postMultipart(baseUrl, resourcePath, formData) {
        const dialogRequest = DialogRequest.createFromPostMultipartRequest(baseUrl, resourcePath, formData);
        return this.processRequestAndResponse('postMultipart', 'handlePostMultipartResponse', [dialogRequest]);
    }
    getJson(baseUrl, resourcePath, queryParams) {
        const dialogRequest = DialogRequest.createFromGetRequest(baseUrl, resourcePath, queryParams);
        return this.processRequestAndResponse('getJson', 'handleGetJsonResponse', [dialogRequest]);
    }
    postJson(baseUrl, resourcePath, jsonBody) {
        const dialogRequest = DialogRequest.createFromPostRequest(baseUrl, resourcePath, jsonBody);
        return this.processRequestAndResponse('postJson', 'handlePostJsonResponse', [dialogRequest]);
    }
    putJson(baseUrl, resourcePath, jsonBody) {
        const dialogRequest = DialogRequest.createFromPutRequest(baseUrl, resourcePath, jsonBody);
        return this.processRequestAndResponse('putJson', 'handlePutJsonResponse', [dialogRequest]);
    }
    deleteJson(baseUrl, resourcePath) {
        const dialogRequest = DialogRequest.createFromDeleteRequest(baseUrl, resourcePath);
        return this.processRequestAndResponse('deleteJson', 'handleDeleteJsonResponse', [dialogRequest]);
    }
    static delegateRequest(previousPr, delegateIterator, requestFn, args) {
        return __awaiter(this, void 0, void 0, function* () {
            const thisMethod = 'DialogProxy::delegateRequest';
            yield previousPr;
            if (delegateIterator.done()) {
                // Log.info(`${thisMethod} -- using common fetch client to process request: ${requestFn}`);
                const fetchClient = DialogProxyTools.commonFetchClient();
                const fetchClientParams = args[0].fetchClientParams();
                return fetchClient[requestFn].apply(fetchClient, fetchClientParams);
            }
            // Select next delegate
            const nextDelegate = delegateIterator.next();
            const nextPr = nextDelegate[requestFn].apply(nextDelegate, args);
            if (!nextPr) {
                // Next delegate chose to immediately skip this request, so advance to the next delegate
                return this.delegateRequest(previousPr, delegateIterator, requestFn, args);
            }
            const response = yield nextPr;
            if (!response) {
                // Next delegate chose to skip this request after a delay, so advance to the next delegate
                // Log.info(`${thisMethod} -- delegate returned a falsey response, advancing to the next delegate with request: ${requestFn}`);
                return this.delegateRequest(nextPr, delegateIterator, requestFn, args);
            }
            // Next delegate produced a response, so this is the future that will be processed
            return nextPr;
        });
    }
    prepareForActivity() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this._initialized) {
                // Log.info("DialogProxy::prepareForActivity -- waiting for all DialogDelegates to initialize");
                const allDelegatesInitializing = this._dialogDelegateChain.map(d => d.initialize(this));
                yield Promise.all(allDelegatesInitializing);
                this._initialized = true;
                // Log.info("DialogProxy::prepareForActivity -- all DialogDelegates are initialized");
                // Log.info("DialogProxy::prepareForActivity -- DialogProxy is initialized");
                this._initializedResolveFn(this._initialized);
            }
            this._lastActivity = new Date();
            return this._initializedPr;
        });
    }
    processRequestAndResponse(requestFn, responseFn, args) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.prepareForActivity();
            const delegateIterator = new ValueIterator(this._dialogDelegateChain);
            let responsePr = DialogProxy.delegateRequest(Promise.resolve(), delegateIterator, requestFn, args);
            for (const d of this._dialogDelegateChain) {
                const argsWithResponse = args.slice(0);
                argsWithResponse.push(responsePr);
                responsePr = d[responseFn].apply(d, argsWithResponse);
            }
            return responsePr;
        });
    }
}
