text: //
  //  PPOTCheckoutRequest.m
  //  PayPalOneTouch
  //
  //  Copyright © 2015 PayPal, Inc. All rights reserved.
  //
  
  #import "PPOTRequest_Internal.h"
  #import "PPOTCheckoutAppSwitchRequest.h"
  #import "PPOTCheckoutBrowserSwitchRequest.h"
  #import "PPOTConfiguration.h"
  #if __has_include("PayPalUtils.h")
  #import "PPOTDevice.h"
  #import "PPOTMacros.h"
  #else
  #import <PayPalUtils/PPOTDevice.h>
  #import <PayPalUtils/PPOTMacros.h>
  #endif
  
  #pragma mark - PPOTCheckoutRequest implementation
  
  @implementation PPOTCheckoutRequest
  
  - (instancetype)initWithApprovalURL:(NSURL *)approvalURL
                            pairingId:(NSString *)pairingId
                             clientID:(NSString *)clientID
                          environment:(NSString *)environment
                    callbackURLScheme:(NSString *)callbackURLScheme {
      if (!approvalURL
          || ([environment isEqualToString:PPRequestEnvironmentProduction]
              && ![approvalURL.absoluteString hasPrefix:@"https://"])) {
              PPSDKLog(@"invalid approval URL, or scheme is not https:");
              return nil;
          }
  
      NSDictionary *queryDictionary = [PPOTAppSwitchUtil parseQueryString:[approvalURL query]];
      NSString *hermesToken = queryDictionary[kPPOTAppSwitchHermesTokenKey];
      if (!hermesToken) {
          hermesToken = queryDictionary[kPPOTAppSwitchHermesBATokenKey];
      }
  
      if (!hermesToken) {
          PPSDKLog(@"approval URL lacks a Hermes token");
          return nil;
      }
  
      self = [super initWithClientID:clientID
                         environment:environment
                   callbackURLScheme:callbackURLScheme];
      if (self) {
          _approvalURL = approvalURL;
  
          _pairingId = pairingId;
      }
      return self;
  }
  
  + (instancetype)requestWithApprovalURL:(NSURL *)approvalURL
                                clientID:(NSString *)clientID
                             environment:(NSString *)environment
                       callbackURLScheme:(NSString *)callbackURLScheme {
      return [PPOTCheckoutRequest requestWithApprovalURL:approvalURL
                                               pairingId:nil
                                                clientID:clientID
                                             environment:environment
                                       callbackURLScheme:callbackURLScheme];
  }
  
  + (instancetype)requestWithApprovalURL:(NSURL *)approvalURL
                               pairingId:(NSString *)pairingId
                                clientID:(NSString *)clientID
                             environment:(NSString *)environment
                       callbackURLScheme:(NSString *)callbackURLScheme {
      PPOTCheckoutRequest *request = [[[self class] alloc] initWithApprovalURL:approvalURL
                                                                     pairingId:pairingId
                                                                      clientID:clientID
                                                                   environment:environment
                                                             callbackURLScheme:callbackURLScheme];
      return request;
  }
  
  #pragma mark - add subclass-specific info to appSwitchRequest
  
  - (PPOTSwitchRequest *)getAppSwitchRequestForConfigurationRecipe:(PPOTConfigurationRecipe *)configurationRecipe {
      PPOTCheckoutSwitchRequest *appSwitchRequest = nil;
  
      switch (configurationRecipe.target) {
          case PPOTRequestTargetOnDeviceApplication: {
              appSwitchRequest = [[PPOTCheckoutAppSwitchRequest alloc] initWithProtocolVersion:configurationRecipe.protocolVersion
                                                                                       appGuid:[PPOTDevice appropriateIdentifier]
                                                                                      clientID:self.clientID
                                                                                   environment:self.environment
                                                                             callbackURLScheme:self.callbackURLScheme
                                                                                     pairingId:self.pairingId];
              break;
          }
          case PPOTRequestTargetBrowser: {
              PPOTCheckoutBrowserSwitchRequest *browserSwitchRequest =
              [[PPOTCheckoutBrowserSwitchRequest alloc] initWithProtocolVersion:configurationRecipe.protocolVersion
                                                                        appGuid:[PPOTDevice appropriateIdentifier]
                                                                       clientID:self.clientID
                                                                    environment:self.environment
                                                              callbackURLScheme:self.callbackURLScheme
                                                                      pairingId:self.pairingId];
              appSwitchRequest = browserSwitchRequest;
              break;
          }
          default: {
              break;
          }
      }
  
      if (appSwitchRequest) {
          appSwitchRequest.targetAppURLScheme = configurationRecipe.targetAppURLScheme;
          appSwitchRequest.responseType = PPAppSwitchResponseTypeWeb;
          appSwitchRequest.approvalURL = [self.approvalURL absoluteString];
      }
  
      return appSwitchRequest;
  }
  
  #pragma mark - configuration methods
  
  - (void)getAppropriateConfigurationRecipe:(void (^)(PPOTConfigurationRecipe *configurationRecipe))completionBlock {
      PPAssert(completionBlock, @"getAppropriateConfigurationRecipe: completionBlock is required");
  
      PPOTConfiguration *currentConfiguration = [PPOTConfiguration getCurrentConfiguration];
      PPOTConfigurationCheckoutRecipe *bestConfigurationRecipe = nil;
      for (PPOTConfigurationCheckoutRecipe *configurationRecipe in currentConfiguration.prioritizedCheckoutRecipes) {
          if (![self isConfigurationRecipeTargetSupported:configurationRecipe] ||
              ![self isConfigurationRecipeLocaleSupported:configurationRecipe]) {
              continue;
          }
          bestConfigurationRecipe = configurationRecipe;
          break;
      }
      
      completionBlock(bestConfigurationRecipe);
  }
  
  @end
  