/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
import { BentleyStatus } from "@itwin/core-bentley";
import { IModelError } from "../../IModelError";
import { RpcResponseCacheControl } from "./RpcConstants";
import { OPERATION, POLICY, RpcRegistry } from "./RpcRegistry";
/** The policy for an RPC operation.
 * @internal
 */
export class RpcOperationPolicy {
    /** Supplies the IModelRpcProps for an operation request. */
    token = (request) => request.findTokenPropsParameter();
    /** Supplies the initial retry interval for an operation request. */
    retryInterval = (configuration) => configuration.pendingOperationRetryInterval;
    /** Called before every operation request on the frontend is sent. */
    requestCallback = (_request) => { };
    /** Called after every operation request on the frontend is sent. */
    sentCallback = (_request) => { };
    /**
     * Determines if caching is permitted for an operation response.
     * @note Not all RPC protocols support caching.
     */
    allowResponseCaching = (_request) => RpcResponseCacheControl.None;
    /** Forces RpcConfiguration.strictMode for this operation. */
    forceStrictMode = false;
    /** Whether the IModelRpcProps in the operation parameter list is allowed to differ from the token in the request URL. */
    allowTokenMismatch = false;
    /** Whether to compress the operation response with one of the client's supported encodings. */
    allowResponseCompression = true;
}
/** An RPC operation descriptor.
 * @internal
 */
export class RpcOperation {
    /** A fallback token to use for RPC requests that do not semantically depend on an iModel. */
    static fallbackToken = undefined;
    /** Looks up an RPC operation by name. */
    static lookup(target, operationName) {
        const definition = typeof (target) === "string" ? RpcRegistry.instance.lookupInterfaceDefinition(target) : target;
        const propertyName = RpcOperation.computeOperationName(operationName);
        const proto = definition.prototype;
        if (!proto.hasOwnProperty(propertyName))
            throw new IModelError(BentleyStatus.ERROR, `RPC interface class "${definition.interfaceName}" does not does not declare operation "${operationName}"`);
        return proto[propertyName][OPERATION];
    }
    /** Iterates the operations of an RPC interface definition. */
    static forEach(definition, callback) {
        Object.getOwnPropertyNames(definition.prototype).forEach((operationName) => {
            if (operationName === "constructor" || operationName === "configurationSupplier")
                return;
            const propertyName = RpcOperation.computeOperationName(operationName);
            callback(definition.prototype[propertyName][OPERATION]);
        });
    }
    /** The RPC interface definition for this operation. */
    interfaceDefinition;
    /** The name of this operation. */
    operationName;
    /** The version of this operation. */
    get interfaceVersion() { return this.interfaceDefinition.interfaceVersion; }
    /** The policy for this operation. */
    policy;
    /** @internal */
    constructor(definition, operation, policy) {
        this.interfaceDefinition = definition;
        this.operationName = operation;
        this.policy = policy;
    }
    /** @internal */
    static computeOperationName(identifier) {
        const c = identifier.indexOf(":");
        if (c === -1)
            return identifier;
        return identifier.substring(0, c + 1);
    }
}
/** @internal */
(function (RpcOperation) {
    function obtainInstance(obj) {
        if (obj instanceof RpcOperationPolicy) {
            return obj;
        }
        else {
            const instance = new RpcOperationPolicy();
            Object.assign(instance, obj);
            return instance;
        }
    }
    /** Decorator for setting the policy for an RPC operation function. */
    function setPolicy(policy) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[OPERATION] = new RpcOperation(target.constructor, propertyKey, obtainInstance(policy));
        };
    }
    RpcOperation.setPolicy = setPolicy;
    /** Convenience decorator for setting an RPC operation policy that allows response caching. */
    function allowResponseCaching(control = RpcResponseCacheControl.Immutable) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[OPERATION] = new RpcOperation(target.constructor, propertyKey, new class extends RpcOperationPolicy {
                allowResponseCaching = () => control;
            }());
        };
    }
    RpcOperation.allowResponseCaching = allowResponseCaching;
    /** Convenience decorator for setting an RPC operation policy that supplies the IModelRpcProps for an operation. */
    function setRoutingProps(handler) {
        return (target, propertyKey, descriptor) => {
            descriptor.value[OPERATION] = new RpcOperation(target.constructor, propertyKey, new class extends RpcOperationPolicy {
                token = handler;
            }());
        };
    }
    RpcOperation.setRoutingProps = setRoutingProps;
    /** Decorator for setting the default policy for an RPC interface definition class. */
    function setDefaultPolicy(policy) {
        return (definition) => {
            definition[POLICY] = obtainInstance(policy);
        };
    }
    RpcOperation.setDefaultPolicy = setDefaultPolicy;
})(RpcOperation || (RpcOperation = {}));
//# sourceMappingURL=RpcOperation.js.map