public static ReshapeResult TryReshape(
            [NotNull] ReshapeGrpc.ReshapeGrpcClient rpcClient,
            [NotNull] IList <Feature> selectedFeatures,
            [NotNull] Polyline reshapeLine,
            [CanBeNull] IList <Feature> adjacentFeatures,
            bool allowOpenJawReshape,
            bool multiReshapeAsUnion,
            bool tryReshapeNonDefault,
            CancellationToken cancellationToken)
        {
            var allInputFeatures = new Dictionary <GdbObjectReference, Feature>();

            AddInputFeatures(selectedFeatures, allInputFeatures);

            var request = CreateReshapeRequest(
                selectedFeatures, reshapeLine, adjacentFeatures, allowOpenJawReshape,
                multiReshapeAsUnion, tryReshapeNonDefault);

            request.AllowOpenJawReshape = true;

            // TODO: If the server is overwhelmed by requests, the calls block (and cannot even be cancelled)
            //       Add a task scheduler mode that throws if no free thread is available immediately
            const int deadline = 2000;

            AdvancedReshapeResponse reshapeResultMsg = RpcCallUtils.Try(
                o => rpcClient.AdvancedReshape(request, o),
                cancellationToken, deadline, true);

            if (reshapeResultMsg == null)
            {
                return(null);
            }

            var result = new ReshapeResult
            {
                OpenJawReshapeHappened   = reshapeResultMsg.OpenJawReshapeHappened,
                OpenJawIntersectionCount = reshapeResultMsg.OpenJawIntersectionCount,
                FailureMessage           = reshapeResultMsg.WarningMessage
            };

            if (reshapeResultMsg.ResultFeatures.Count == 0)
            {
                return(result);
            }

            foreach (ResultFeatureMsg resultFeatureMsg in reshapeResultMsg.ResultFeatures)
            {
                GdbObjectReference objRef = new GdbObjectReference(
                    resultFeatureMsg.UpdatedFeature.ClassHandle,
                    resultFeatureMsg.UpdatedFeature.ObjectId);

                Feature inputFeature = allInputFeatures[objRef];

                var reshapeResultFeature = new ReshapeResultFeature(inputFeature, resultFeatureMsg);

                result.ResultFeatures.Add(reshapeResultFeature);
            }

            return(result);
        }
        private static ReshapeResult Reshape(
            [NotNull] ReshapeGrpc.ReshapeGrpcClient rpcClient,
            [NotNull] AdvancedReshapeRequest request,
            [NotNull] IReadOnlyDictionary <GdbObjectReference, Feature> allInputFeatures,
            CancellationToken cancellationToken)
        {
            request.AllowOpenJawReshape = true;

            const int deadlinePerFeature = 5000;

            AdvancedReshapeResponse reshapeResultMsg = RpcCallUtils.Try(
                o => rpcClient.AdvancedReshape(request, o),
                cancellationToken, deadlinePerFeature * request.Features.Count);

            if (reshapeResultMsg == null)
            {
                return(null);
            }

            var result = new ReshapeResult
            {
                OpenJawReshapeHappened   = reshapeResultMsg.OpenJawReshapeHappened,
                OpenJawIntersectionCount = reshapeResultMsg.OpenJawIntersectionCount,
                FailureMessage           = reshapeResultMsg.WarningMessage
            };

            if (reshapeResultMsg.ResultFeatures.Count == 0)
            {
                return(result);
            }

            foreach (ResultFeatureMsg resultFeatureMsg in reshapeResultMsg.ResultFeatures)
            {
                GdbObjectReference objRef = new GdbObjectReference(
                    resultFeatureMsg.UpdatedFeature.ClassHandle,
                    resultFeatureMsg.UpdatedFeature.ObjectId);

                Feature inputFeature = allInputFeatures[objRef];

                var reshapeResultFeature = new ReshapeResultFeature(inputFeature, resultFeatureMsg);

                result.ResultFeatures.Add(reshapeResultFeature);
            }

            return(result);
        }