#import <string>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Cordova/CDV.h>
#import <PokktSDK/PokktSDK.h>


/***
 *
 *  CONSTS
 *
 ***/

// Operation Names

#define     SET_POKKT_CONFIG                @"setPokktConfig"
#define     SET_THIRDPARTY_ID               @"setThirdPartyUserId"
#define     SET_PLAYER_VIEW_CONFIG          @"setAdPlayerViewConfig"
#define     SET_USER_DETAILS                @"setUserDetails"
#define     SET_CALLBACK_EXTRA_PARAMS       @"setCallbackExtraParams"

#define     VIDEO_AD_CACHE_REWARDED                     @"VideoAd_cacheRewarded"
#define     VIDEO_AD_CACHE_NON_REWARDED                 @"VideoAd_cacheNonRewarded"
#define     VIDEO_AD_SHOW_REWARDED                      @"VideoAd_showRewarded"
#define     VIDEO_AD_SHOW_NON_REWARDED                  @"VideoAd_showNonRewarded"

#define     INTERSTITIAL_AD_CACHE_REWARDED                      @"Interstitial_cacheRewarded"
#define     INTERSTITIAL_AD_CACHE_NON_REWARDED                  @"Interstitial_cacheNonRewarded"
#define     INTERSTITIAL_AD_SHOW_REWARDED                       @"Interstitial_showRewarded"
#define     INTERSTITIAL_AD_SHOW_NON_REWARDED                   @"Interstitial_showNonRewarded"

#define     BANNER_LOAD                     @"Banner_loadBanner"
#define     BANNER_LOAD_WITH_RECT           @"Banner_loadBannerWithRect"
#define     BANNER_DESTROY                  @"Banner_destroyBanner"

#define     IN_GAME_ADS_FETCH_ASSETS        @"InGameAd_fetchAssets"
#define     IN_GAME_ADS_TRACK_FU_CLICK      @"InGameAd_trackFUClick"
#define     IN_GAME_ADS_UPDATE_IGA_DATA     @"InGameAd_updateIGAData"

#define     ANALYTICS_SET_DETAILS           @"Analytics_setAnalyticsDetails"
#define     ANALYTICS_TRACK_IAP             @"Analytics_trackIAP"

#define     DEBUGGING_SHOULD_DEBUG          @"Debugging_shouldDebug"
#define     DEBUGGING_EXPORT_LOG            @"Debugging_exportLog"
#define     DEBUGGING_EXPORT_LOG_TO_CLOUD   @"Debugging_exportLogToCloud"
#define     DEBUGGING_SHOW_TOAST            @"Debugging_showToast"
#define     DEBUGGING_SHOW_LOG              @"Debugging_showLog"


/***
 *  Pokkt-to-Framework Events
 ***/

// Video Ad Related Events
#define EVENT_VIDEO_AD_CACHING_COMPLETED                      @"VideoAdCachingCompleted"
#define EVENT_VIDEO_AD_CACHING_FAILED                         @"VideoAdCachingFailed"
#define EVENT_VIDEO_AD_CLOSED                                 @"VideoAdClosed"
#define EVENT_VIDEO_AD_COMPLETED                              @"VideoAdCompleted"
#define EVENT_VIDEO_AD_FAILED_TO_SHOW                         @"VideoAdFailedToShow"
#define EVENT_VIDEO_AD_DISPLAYED                              @"VideoAdDisplayed"
#define EVENT_VIDEO_AD_SKIPPED                                @"VideoAdSkipped"
#define EVENT_VIDEO_AD_GRATIFIED                              @"VideoAdGratified"

// Interstitial Related Events
#define EVENT_INTERSTITIAL_CACHING_COMPLETED                      @"InterstitialCachingCompleted"
#define EVENT_INTERSTITIAL_CACHING_FAILED                         @"InterstitialCachingFailed"
#define EVENT_INTERSTITIAL_CLOSED                                 @"InterstitialClosed"
#define EVENT_INTERSTITIAL_COMPLETED                              @"InterstitialCompleted"
#define EVENT_INTERSTITIAL_FAILED_TO_SHOW                         @"InterstitialFailedToShow"
#define EVENT_INTERSTITIAL_DISPLAYED                              @"InterstitialDisplayed"
#define EVENT_INTERSTITIAL_SKIPPED                                @"InterstitialSkipped"
#define EVENT_INTERSTITIAL_GRATIFIED                              @"InterstitialGratified"

// Banner Ad Delegate
#define EVENT_BANNER_LOADED                   @"BannerLoaded"
#define EVENT_BANNER_LOAD_FAILED              @"BannerLoadFailed"

// IGA Delegate
#define EVENT_IGA_ASSETS_READY                @"IGAAssetsReady"
#define EVENT_IGA_ASSETS_FAILED               @"IGAAssetsFailed"


// banner related
#define TOP_LEFT        1
#define TOP_CENTER      2
#define TOP_RIGHT       3
#define MIDDLE_LEFT     4
#define MIDDLE_CENTER   5
#define MIDDLE_RIGHT    6
#define BOTTOM_LEFT     7
#define BOTTOM_CENTER   8
#define BOTTOM_RIGHT    9




/***
 *
 * DEFINITIONS
 *
 ***/

typedef void (^CaseBlock)(NSString* params);


// utils
void notifyFramework(NSString *operation, NSString *param);
UIViewController* getRootViewController();
NSDictionary* extractJSON(NSString* jsonString);
PokktIAPDetails* parseIAPDetails(NSString* detailsString);
PokktAdPlayerViewConfig* getAdPlayerViewConfigFromJSONString(NSString* configString);
PokktUserInfo* getUserDetailsFromJSONString(NSString* stringData);
PokktAnalyticsDetails* getAnalyticsDetailsFromJSONString(NSString* stringData);
NSString* stringifyJSONDictionary(NSDictionary *jsonObject);
NSString* getReturnParamsFromValues(NSString* _Nonnull screenName, bool isRewarded, NSMutableDictionary<NSString *, id> *paramList);


// banner-util methods
void topLeft(UIView * view);
void topRight(UIView * view);
void topCenter(UIView * view);
void middleLeft(UIView* view);
void middleRight(UIView * view);
void middleCenter(UIView * view);
void bottomLeft(UIView * view);
void bottomRight(UIView * view);
void bottomCenter(UIView * view);




/***
 *
 * ADAPTER
 *
 ***/

static PokktBannerView* bannerContainer;
static NSDictionary *operations = nil;

static BOOL delegateAssigned = false;

@interface PokktAdsAdapter : NSObject<PokktVideoAdsDelegate, PokktInterstitialDelegate, PokktBannerDelegate, PokktIGADelegate>

+ (void) processForOperation:(NSString*)operation withParams:(NSString*)params;

@end




/***
 *
 *  NATIVE EXTENSION
 *  - these are exposed to the framework
 *  - frameworks will call these to communicate
 *
 ***/

void notifyNative(NSString *operation, NSString *params)
{
    [PokktAdsAdapter processForOperation:operation withParams:params];
    
    if (!delegateAssigned)
    {
        PokktAdsAdapter *adapter = [[PokktAdsAdapter alloc] init];
        [PokktVideoAds setPokktVideoAdsDelegate:adapter];
        [PokktInterstitial setPokktInterstitialDelegate:adapter];
        [PokktBanner setPokktBannerDelegate:adapter];
        [PokktInGameAd setIGADelegate:adapter];
        
        delegateAssigned = true;
    }
}

void notifyNative(const char *operation, const char *params)
{
    NSString *op = [NSString stringWithUTF8String:(operation)];
    NSString *prm = [NSString stringWithUTF8String:(params)];
    notifyNative(op, prm);
}

const char* getSDKVersionOnNative()
{
    const char* version = [[NSString stringWithFormat:@"%@", [PokktAds getSDKVersion]] UTF8String];
    return version;
}




/***
 *
 *  ADATPTER: implementation
 *
 ***/

@implementation PokktAdsAdapter

+ (NSDictionary*) getOperationList
{
    if (operations == nil)
    {
        operations =
        @{
          // Common APIs
          SET_POKKT_CONFIG:
              ^(NSString *params) {
                  NSDictionary *jsonObject = extractJSON(params);
                  NSString *appId = jsonObject[@"appId"];
                  NSString *securityKey = jsonObject[@"securityKey"];
                  [PokktAds setPokktConfigWithAppId:appId securityKey:securityKey];
              },
          
          SET_THIRDPARTY_ID:
              ^(NSString *params) {
                  [PokktAds setThirdPartyUserId:params];
              },
          
          SET_PLAYER_VIEW_CONFIG:
              ^(NSString *params) {
                  [PokktAds setPokktAdPlayerViewConfig:getAdPlayerViewConfigFromJSONString(params)];
              },
          
          SET_USER_DETAILS:
              ^(NSString *params) {
                  [PokktAds setUserDetails:getUserDetailsFromJSONString(params)];
              },
        
          SET_CALLBACK_EXTRA_PARAMS:
              ^(NSString *params){
                  NSDictionary *paramDict = extractJSON(params);
                  [PokktAds setCallbackExtraParam:paramDict];
              },
          
          // Video Ads APIs
          VIDEO_AD_CACHE_REWARDED:
              ^(NSString *params) {
                  [PokktVideoAds cacheRewarded:params];
              },
          
          VIDEO_AD_CACHE_NON_REWARDED:
              ^(NSString *params) {
                  [PokktVideoAds cacheNonRewarded:params];
              },
          
          VIDEO_AD_SHOW_REWARDED:
              ^(NSString *params) {
                  [PokktVideoAds showRewarded:params withViewController:getRootViewController()];
              },
          
          VIDEO_AD_SHOW_NON_REWARDED:
              ^(NSString *params) {
                  [PokktVideoAds showNonRewarded:params withViewController:getRootViewController()];
              },
          
          
          // Interstitial APIs
          INTERSTITIAL_AD_CACHE_REWARDED:
              ^(NSString *params) {
                  [PokktInterstitial cacheRewarded:params];
              },
          
          INTERSTITIAL_AD_CACHE_NON_REWARDED:
              ^(NSString *params) {
                  [PokktInterstitial cacheNonRewarded:params];
              },
          
          INTERSTITIAL_AD_SHOW_REWARDED:
              ^(NSString *params) {
                  [PokktInterstitial showRewarded:params withViewController:getRootViewController()];
              },
          
          INTERSTITIAL_AD_SHOW_NON_REWARDED:
              ^(NSString *params) {
                  [PokktInterstitial showNonRewarded:params withViewController:getRootViewController()];
              },
          
          
          // Banner Ads APIs
          BANNER_LOAD:
              ^(NSString *params) {
                  NSDictionary *jsonObject = extractJSON(params);
                  
                  NSString* screenName = jsonObject[@"screenName"];
                  int position = [jsonObject[@"bannerPosition"] intValue];
                  
                  if (bannerContainer != NULL)
                  {
                      [PokktBanner destroyBanner:bannerContainer];
                      bannerContainer = NULL;
                  }
                  
                  bannerContainer = [[PokktBannerView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
                  bannerContainer.translatesAutoresizingMaskIntoConstraints = NO;
                  
                  [getRootViewController().view addSubview:bannerContainer];
                  
                  switch (position)
                  {
                      case 1: topLeft(bannerContainer);       break;
                      case 2: topCenter(bannerContainer);     break;
                      case 3: topRight(bannerContainer);      break;
                      case 4: middleLeft(bannerContainer);    break;
                      case 5: middleCenter(bannerContainer);  break;
                      case 6: middleRight(bannerContainer);   break;
                      case 7: bottomLeft(bannerContainer);    break;
                      case 8: bottomCenter(bannerContainer);  break;
                      case 9: bottomRight(bannerContainer);   break;
                      default: topCenter(bannerContainer);    break;
                  }
                  
                  [PokktBanner loadBanner:bannerContainer withScreenName:screenName rootViewContorller:getRootViewController()];
              },
          
          BANNER_LOAD_WITH_RECT:
              ^(NSString *params) {
                  NSDictionary *jsonObject = extractJSON(params);
                  
                  NSString *screenName = jsonObject[@"screenName"];
                  int width = [jsonObject[@"width"] intValue];
                  int height = [jsonObject[@"height"] intValue];
                  float x = [jsonObject[@"x"] floatValue];
                  float y = [jsonObject[@"y"]floatValue];
                  
                  if (bannerContainer != NULL)
                  {
                      [PokktBanner destroyBanner:bannerContainer];
                      bannerContainer = NULL;
                  }
                  
                  bannerContainer = [[PokktBannerView alloc] initWithFrame:CGRectMake(x, y, width, height)];
                  [getRootViewController().view addSubview:bannerContainer];
                  
                  [PokktBanner loadBanner:bannerContainer withScreenName:screenName rootViewContorller:getRootViewController()];
              },
          
          BANNER_DESTROY:
              ^(NSString *params) {
                  [PokktBanner destroyBanner:bannerContainer];
              },
          
          // IGA APIs
          IN_GAME_ADS_FETCH_ASSETS:
              ^(NSString *params) {
                  [PokktInGameAd fetchIGAAssets:params];
              },
          
          IN_GAME_ADS_UPDATE_IGA_DATA:
              ^(NSString *params) {
                  [PokktAds updateIGAData:params];
              },
          
          IN_GAME_ADS_TRACK_FU_CLICK:
              ^(NSString *params) {
                  [PokktDebugger printLog:@"InGameAd_trackFUClick - TODO"];
                  // TODO
              },
          
          
          // Analytics APIs
          ANALYTICS_SET_DETAILS:
              ^(NSString *params) {
                  [PokktAds setPokktAnalyticsDetail:getAnalyticsDetailsFromJSONString(params)];
              },
          
          ANALYTICS_TRACK_IAP:
              ^(NSString *params) {
                  [PokktAds trackIAP:parseIAPDetails(params)];
              },
          
          
          // Debugging APIs
          DEBUGGING_SHOULD_DEBUG:
              ^(NSString *params) {
                  [PokktDebugger setDebug:[params boolValue]];
              },
          
          DEBUGGING_SHOW_LOG:
              ^(NSString *params) {
                  [PokktDebugger printLog:params];
              },
          
          DEBUGGING_SHOW_TOAST:
              ^(NSString *params) {
                  [PokktDebugger showToast:params viewController:getRootViewController()];
              },
          
          DEBUGGING_EXPORT_LOG:
              ^(NSString *params) {
                  [PokktDebugger exportLog:getRootViewController()];
              },
          
          DEBUGGING_EXPORT_LOG_TO_CLOUD:
              ^(NSString *params) {
                  [PokktDebugger printLog:@"Debugging_exportLogToCloud is not implemented in iOS!"];
              }
          };
    }
    
    return operations;
}

+ (void) processForOperation:(NSString*)operation withParams:(NSString*)params
{
    NSDictionary *opsList = [self getOperationList];
    CaseBlock block = (CaseBlock)opsList[operation];
    if (block)
    {
        block(params);
    }
    else
    {
        NSLog(@"[POKKT-NATIVE] Unknown operation requested: %@", operation);
    }
}


/***
 * Video Ad Delegate
 ***/

- (void) videoAdCachingCompleted:(NSString *) screenName isRewarded: (BOOL)isRewarded reward: (float)reward
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"REWARD"] = [[NSNumber numberWithFloat:reward] stringValue];
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_VIDEO_AD_CACHING_COMPLETED, params);
}

- (void) videoAdCachingFailed: (NSString *)screenName isRewarded: (BOOL)isRewarded errorMessage: (NSString *)errorMessage
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"ERROR_MESSAGE"] = errorMessage;
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_VIDEO_AD_CACHING_FAILED, params);
}

- (void) videoAdCompleted: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_VIDEO_AD_COMPLETED, params);
}

- (void) videoAdDisplayed: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_VIDEO_AD_DISPLAYED, params);
}

- (void) videoAdGratified: (NSString *)screenName reward:(float)reward
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"REWARD"] = [[NSNumber numberWithFloat:reward] stringValue];
    NSString *params = getReturnParamsFromValues(screenName, true, additionalParams);
    
    notifyFramework(EVENT_VIDEO_AD_GRATIFIED, params);
}

- (void) videoAdSkipped: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_VIDEO_AD_SKIPPED, params);
}

- (void) videoAdClosed:(NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_VIDEO_AD_CLOSED, params);
}

- (void) videoAdAvailabilityStatus: (NSString *)screenName isRewarded: (BOOL)isRewarded isAdAvailable: (BOOL)isAdAvailable
{
    // IGNORE
}

- (void) videoAdFailedToShow: (NSString *)screenName isRewarded: (BOOL)isRewarded errorMessage: (NSString *)errorMessage
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"ERROR_MESSAGE"] = errorMessage;
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_VIDEO_AD_FAILED_TO_SHOW, params);
}


/***
 * Interstitial Delegate
 ***/

- (void) interstitialCachingCompleted:(NSString *) screenName isRewarded: (BOOL)isRewarded reward: (float)reward
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"REWARD"] = [[NSNumber numberWithFloat:reward] stringValue];
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_INTERSTITIAL_CACHING_COMPLETED, params);
}

- (void) interstitialCachingFailed: (NSString *)screenName isRewarded: (BOOL)isRewarded errorMessage: (NSString *)errorMessage
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"ERROR_MESSAGE"] = errorMessage;
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_INTERSTITIAL_CACHING_FAILED, params);
}

- (void) interstitialCompleted: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_INTERSTITIAL_COMPLETED, params);
}

- (void) interstitialDisplayed: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_VIDEO_AD_DISPLAYED, params);
}

- (void) interstitialGratified: (NSString *)screenName reward:(float)reward
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"REWARD"] = [[NSNumber numberWithFloat:reward] stringValue];
    NSString *params = getReturnParamsFromValues(screenName, true, additionalParams);
    
    notifyFramework(EVENT_INTERSTITIAL_GRATIFIED, params);
}

- (void) interstitialSkipped: (NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_INTERSTITIAL_SKIPPED, params);
}

- (void) interstitialClosed:(NSString *)screenName isRewarded: (BOOL)isRewarded
{
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, nil);
    
    notifyFramework(EVENT_INTERSTITIAL_CLOSED, params);
}

- (void) interstitialAvailabilityStatus: (NSString *)screenName isRewarded: (BOOL)isRewarded isAdAvailable: (BOOL)isAdAvailable
{
    // IGNORE
}

- (void) interstitialFailedToShow: (NSString *)screenName isRewarded: (BOOL)isRewarded errorMessage: (NSString *)errorMessage
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"ERROR_MESSAGE"] = errorMessage;
    NSString *params = getReturnParamsFromValues(screenName, isRewarded, additionalParams);
    
    notifyFramework(EVENT_INTERSTITIAL_FAILED_TO_SHOW, params);
}


/***
 * Banner Ads Delegate
 ***/

- (void)bannerLoaded:(NSString *)screenName
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"SCREEN_NAME"] = screenName;
    NSString *params = stringifyJSONDictionary(additionalParams);
    notifyFramework(EVENT_BANNER_LOADED, params);
}

- (void)bannerLoadFailed:(NSString *)screenName errorMessage:(NSString *)errorMessage
{
    NSMutableDictionary *additionalParams = [[NSMutableDictionary alloc] init];
    additionalParams[@"SCREEN_NAME"] = screenName;
    additionalParams[@"ERROR_MESSAGE"] = errorMessage;
    NSString *params = stringifyJSONDictionary(additionalParams);
    
    notifyFramework(EVENT_BANNER_LOAD_FAILED, params);
}


/***
 * IGA Delegate
 ***/

- (void)onIGAAssetsReady:(NSString *)screenName igaAssets:(NSString *)igaAssets
{
    notifyFramework(EVENT_IGA_ASSETS_READY, igaAssets);
}

- (void)onIGAAssetsFailed:(NSString *)screenName errorMessage:(NSString *)errorMessage
{
    notifyFramework(EVENT_IGA_ASSETS_FAILED, errorMessage);
}

@end




/***
 *
 * UTILITIES
 *
 ***/

UIViewController* getRootViewController()
{
    UIViewController *viewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    return viewController;
}

NSDictionary* extractJSON(NSString* jsonString)
{
    NSError* jsonError;
    NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary* jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData
                                                               options:NSJSONReadingMutableContainers
                                                                 error:&jsonError];
    return jsonObject;
}

PokktIAPDetails* parseIAPDetails(NSString* detailsString)
{
    NSDictionary* jsonObject = extractJSON(detailsString);
    
    PokktIAPDetails* details = [[PokktIAPDetails alloc] init];
    
    details.productIdentifier = jsonObject[@"productId"];
    details.productPrice = [NSString stringWithFormat:@"%d", [jsonObject[@"price"] intValue]];
    details.productCurrency = jsonObject[@"currencyCode"];
    details.productTitle = jsonObject[@"title"];
    details.productDescription = jsonObject[@"description"];
    
    // TODO
    //detail.setPurchaseData(jsonObject.optString("purchaseData"));
    //detail.setPurchaseSignature(jsonObject.optString("purchaseSignature"));
    //detail.setPurchaseStore(IAPStoreType.valueOf(jsonObject.optString("purchaseStore")));
    
    return details;
}

PokktAdPlayerViewConfig* getAdPlayerViewConfigFromJSONString(NSString* configString)
{
    NSDictionary* jsonObject = extractJSON(configString);
    
    PokktAdPlayerViewConfig* config = [[PokktAdPlayerViewConfig alloc] init];
    
    config.shouldAllowSkip = [jsonObject[@"shouldAllowSkip"] boolValue];
    config.defaultSkipTime = [jsonObject[@"defaultSkipTime"] floatValue];
    config.skipConfirmMessage = jsonObject[@"skipConfirmMessage"];
    config.shouldAllowMute = [jsonObject[@"shouldAllowMute"] boolValue];
    config.shouldConfirmSkip = [jsonObject[@"shouldSkipConfirm"] boolValue];
    config.shouldCollectFeedback = [jsonObject[@"shouldCollectFeedback"] boolValue];
    config.isAudioEnabled = [jsonObject[@"isAudioEnabled"] boolValue];
    config.skipConfirmYesLabel = jsonObject[@"skipConfirmYesLabel"];
    config.skipConfirmNoLabel = jsonObject[@"skipConfirmNoLabel"];
    config.skipTimerMessage = jsonObject[@"skipTimerMessage"];
    config.incentiveMessage = jsonObject[@"incentiveMessage"];
    
    return config;
}

PokktUserInfo* getUserDetailsFromJSONString(NSString* stringData)
{
    NSDictionary *jsonObject = extractJSON(stringData);
    
    PokktUserInfo *info = [[PokktUserInfo alloc] init];
    
    info.name = jsonObject[@"name"];
    info.age = jsonObject[@"age"];
    info.sex = jsonObject[@"sex"];
    info.mobileNumber = jsonObject[@"mobileNo"];
    info.emailAddress = jsonObject[@"emailAddress"];
    info.location = jsonObject[@"location"];
    info.birthday = jsonObject[@"birthday"];
    info.maritalStatus = jsonObject[@"maritalStatus"];
    info.facebookId = jsonObject[@"facebookId"];
    info.twitterHandle = jsonObject[@"twitterHandle"];
    info.educationInformation = jsonObject[@"education"];
    info.nationality = jsonObject[@"nationality"];
    info.employmentStatus = jsonObject[@"employment"];
    info.maturityRating = jsonObject[@"maturityRating"];
    
    return info;
}

PokktAnalyticsDetails* getAnalyticsDetailsFromJSONString(NSString* stringData)
{
    NSDictionary *jsonObject = extractJSON(stringData);
    
    PokktAnalyticsDetails *details = [[PokktAnalyticsDetails alloc] init];
    
    // analytics
    details.googleTrackerID = jsonObject[@"googleAnalyticsID"];
    details.mixPanelTrackerID = jsonObject[@"mixPanelProjectToken"];
    details.flurryTrackerID = jsonObject[@"flurryApplicationKey"];
    
    if (jsonObject[@"selectedAnalyticsType"] != nil && ![jsonObject[@"selectedAnalyticsType"] isEqual:@""])
    {
        if ([jsonObject[@"selectedAnalyticsType"] isEqual:@"FLURRY"])
            details.eventType = FLURRY_ANALYTICS;
        
        else if ([jsonObject[@"selectedAnalyticsType"] isEqual:@"GOOGLE_ANALYTICS"])
            details.eventType = GOOGLE_ANALYTICS;
        
        else if ([jsonObject[@"selectedAnalyticsType"] isEqual:@"MIXPANNEL"])
            details.eventType = MIXPANNEL_ANALYTICS;
    }
    
    return details;
}

NSString* getReturnParamsFromValues(NSString* _Nonnull screenName, bool isRewarded, NSMutableDictionary<NSString *, id> *paramList)
{
    if (!paramList)
    {
        paramList = [[NSMutableDictionary alloc] init];
    }
    
    paramList[@"SCREEN_NAME"] = screenName;
    paramList[@"IS_REWARDED"] = isRewarded ? @true : @false;;
    
    NSString *params = stringifyJSONDictionary(paramList);
    return params;
}


NSString* stringifyJSONDictionary(NSDictionary *jsonObject)
{
    NSError *jsonError;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:&jsonError];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    return jsonString;
}

NSLayoutConstraint* getLayoutConstraint(UIView* view, NSLayoutAttribute layoutAttribute1, NSLayoutRelation layoutRelation, UIView* toItem, NSLayoutAttribute layoutAttribute2, CGFloat multiplier, CGFloat constant)
{
    return [NSLayoutConstraint constraintWithItem:view
                                        attribute:layoutAttribute1
                                        relatedBy:layoutRelation
                                           toItem:toItem
                                        attribute:layoutAttribute2
                                       multiplier:multiplier
                                         constant:constant];
}

void updateBannerLocation(UIView* view, NSLayoutConstraint* leading, NSLayoutConstraint* bottom, NSLayoutConstraint* trailing, NSLayoutConstraint* height)
{
    [view addConstraint:trailing];
    [view.superview addConstraint:bottom];
    [view.superview addConstraint:leading];
    [view addConstraint:height];
}

//Top
void topLeft(UIView* view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeLeft, NSLayoutRelationEqual, view.superview, NSLayoutAttributeLeft, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeTop, NSLayoutRelationEqual, view.superview, NSLayoutAttributeTop, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void topRight(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeRight, NSLayoutRelationEqual, view.superview, NSLayoutAttributeRight, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeTop, NSLayoutRelationEqual, view.superview, NSLayoutAttributeTop, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void topCenter(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeCenterX, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterX, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeTop, NSLayoutRelationEqual, view.superview, NSLayoutAttributeTop, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

// Middle
void middleLeft(UIView* view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeLeft, NSLayoutRelationEqual, view.superview, NSLayoutAttributeLeft, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeCenterY, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterY, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void middleRight(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeRight, NSLayoutRelationEqual, view.superview, NSLayoutAttributeRight, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeCenterY, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterY, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void middleCenter(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeCenterX, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterX, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeCenterY, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterY, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

//Bottom
void bottomLeft(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeLeading, NSLayoutRelationEqual, view.superview, NSLayoutAttributeLeading, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeBottom, NSLayoutRelationEqual, view.superview, NSLayoutAttributeBottom, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void bottomRight(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeRight, NSLayoutRelationEqual, view.superview, NSLayoutAttributeRight, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeBottom, NSLayoutRelationEqual, view.superview, NSLayoutAttributeBottom, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}

void bottomCenter(UIView * view)
{
    NSLayoutConstraint* leading = getLayoutConstraint(view, NSLayoutAttributeCenterX, NSLayoutRelationEqual, view.superview, NSLayoutAttributeCenterX, 1.0f, 0.f);
    NSLayoutConstraint* bottom = getLayoutConstraint(view, NSLayoutAttributeBottom, NSLayoutRelationEqual, view.superview, NSLayoutAttributeBottom, 1.0f, 0.f);
    NSLayoutConstraint* trailing = getLayoutConstraint(view, NSLayoutAttributeWidth, NSLayoutRelationEqual, nil, NSLayoutAttributeWidth, 1.0f, 320);
    NSLayoutConstraint* height = getLayoutConstraint(view, NSLayoutAttributeHeight, NSLayoutRelationEqual, nil, NSLayoutAttributeNotAnAttribute, 0, 50);
    
    updateBannerLocation(view, leading, bottom, trailing, height);
}




/***
 *
 *  POKKT-TO-FRAMEWORK
 *
 ***/
CDVPlugin *cordovaPlugin = nil;

void notifyFramework(NSString *operation, NSString *param)
{
    if (cordovaPlugin != nil)
    {
        NSString *event = [NSString stringWithFormat:@"javascript:cordova.fireDocumentEvent('%@', { 'param': '%@' });", operation, param];
        UIWebView *web = (UIWebView *)[cordovaPlugin webView];
        [web stringByEvaluatingJavaScriptFromString:event];
    }
    else
    {
        NSLog(@"plugin not found!");
    }
}


/***
 *  Framework Specifics
 ***/

@interface PokktNativeExtension : CDVPlugin {}

- (void) pluginInitialize;
- (void) executeSuccessCallback: (CDVInvokedUrlCommand*)command;
- (void) executeErrorCallback: (CDVInvokedUrlCommand*)command;

- (void)setPokktConfig: (CDVInvokedUrlCommand *)command;
- (void)setThirdPartyUserId: (CDVInvokedUrlCommand *)command;
- (void)setAdPlayerViewConfig: (CDVInvokedUrlCommand *)command;
- (void)setUserDetails: (CDVInvokedUrlCommand *)command;

- (void)VideoAd_cacheRewarded: (CDVInvokedUrlCommand *)command;
- (void)VideoAd_cacheNonRewarded: (CDVInvokedUrlCommand *)command;
- (void)VideoAd_showRewarded: (CDVInvokedUrlCommand *)command;
- (void)VideoAd_showNonRewarded: (CDVInvokedUrlCommand *)command;

- (void)Interstitial_cacheRewarded: (CDVInvokedUrlCommand *)command;
- (void)Interstitial_cacheNonRewarded: (CDVInvokedUrlCommand *)command;
- (void)Interstitial_showRewarded: (CDVInvokedUrlCommand *)command;
- (void)Interstitial_showNonRewarded: (CDVInvokedUrlCommand *)command;

- (void)Banner_loadBanner: (CDVInvokedUrlCommand *)command;
- (void)Banner_loadBannerWithRect: (CDVInvokedUrlCommand *)command;
- (void)Banner_destroyBanner: (CDVInvokedUrlCommand *)command;

- (void)Analytics_setAnalyticsDetails: (CDVInvokedUrlCommand *)command;
- (void)Analytics_trackIAP: (CDVInvokedUrlCommand *)command;

- (void)Debugging_shouldDebug: (CDVInvokedUrlCommand *)command;
- (void)Debugging_exportLog: (CDVInvokedUrlCommand *)command;
- (void)Debugging_showToast: (CDVInvokedUrlCommand *)command;
- (void)Debugging_showLog: (CDVInvokedUrlCommand *)command;

@end


@implementation PokktNativeExtension : CDVPlugin

- (void) pluginInitialize
{
    NSLog(@"pokkt plugin initialized!");

    [super pluginInitialize];

    // set cordova plugin
    cordovaPlugin = self;
}

- (void) executeSuccessCallback:(CDVInvokedUrlCommand*)command;
{
    CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void) executeErrorCallback:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}


- (void)setPokktConfig: (CDVInvokedUrlCommand *)command
{
    NSDictionary* args = [command.arguments objectAtIndex:0];
    NSString* jsonString = stringifyJSONDictionary(args);
    notifyNative(SET_POKKT_CONFIG, jsonString);

    [self executeSuccessCallback:command];
}

- (void)setThirdPartyUserId: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(SET_THIRDPARTY_ID, args);

    [self executeSuccessCallback:command];
}

- (void)setAdPlayerViewConfig: (CDVInvokedUrlCommand *)command;
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(SET_PLAYER_VIEW_CONFIG, args);
 
    [self executeSuccessCallback:command];
}

- (void)setUserDetails: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(SET_USER_DETAILS, args);

    [self executeSuccessCallback:command];
}
- (void)setCallbackExtraParams: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(SET_CALLBACK_EXTRA_PARAMS, args);
    
    [self executeSuccessCallback:command];
}


- (void)VideoAd_cacheRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(VIDEO_AD_CACHE_REWARDED, args);
    
    [self executeSuccessCallback:command];
}

- (void)VideoAd_cacheNonRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(VIDEO_AD_CACHE_NON_REWARDED, args);

    [self executeSuccessCallback:command];
}

- (void)VideoAd_showRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(VIDEO_AD_SHOW_REWARDED, args);

    [self executeSuccessCallback:command];
}

- (void)VideoAd_showNonRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(VIDEO_AD_SHOW_NON_REWARDED, args);

    [self executeSuccessCallback:command];
}


- (void)Interstitial_cacheRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(INTERSTITIAL_AD_CACHE_REWARDED, args);

    [self executeSuccessCallback:command];
}

- (void)Interstitial_cacheNonRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(INTERSTITIAL_AD_CACHE_NON_REWARDED, args);

    [self executeSuccessCallback:command];
}

- (void)Interstitial_showRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(INTERSTITIAL_AD_SHOW_REWARDED, args);

    [self executeSuccessCallback:command];
}

- (void)Interstitial_showNonRewarded: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(INTERSTITIAL_AD_SHOW_NON_REWARDED, args);

    [self executeSuccessCallback:command];
}


- (void)Banner_loadBanner: (CDVInvokedUrlCommand *)command
{
    NSDictionary* args = [command.arguments objectAtIndex:0];
    NSString* jsonString = stringifyJSONDictionary(args);
    notifyNative(BANNER_LOAD, jsonString);
    
    [self executeSuccessCallback:command];
}

- (void)Banner_loadBannerWithRect: (CDVInvokedUrlCommand *)command
{
    NSDictionary* args = [command.arguments objectAtIndex:0];
    NSString* jsonString = stringifyJSONDictionary(args);
    notifyNative(BANNER_LOAD_WITH_RECT, jsonString);
    
    [self executeSuccessCallback:command];
}

- (void)Banner_destroyBanner: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(BANNER_DESTROY, args);
    
    [self executeSuccessCallback:command];
}

- (void)Analytics_setAnalyticsDetails: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(ANALYTICS_SET_DETAILS, args);
    
    [self executeSuccessCallback:command];
}

- (void)Analytics_trackIAP: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(ANALYTICS_TRACK_IAP, args);

    [self executeSuccessCallback:command];
}


- (void)Debugging_shouldDebug: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(DEBUGGING_SHOULD_DEBUG, args);
    [self executeSuccessCallback:command];
}

- (void)Debugging_exportLog: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(DEBUGGING_EXPORT_LOG, args);
    
    [self executeSuccessCallback:command];
}

- (void)Debugging_showToast: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(DEBUGGING_SHOW_TOAST, args);
    
    [self executeSuccessCallback:command];
}

- (void)Debugging_showLog: (CDVInvokedUrlCommand *)command
{
    NSString* args = [command.arguments objectAtIndex:0];
    notifyNative(DEBUGGING_SHOW_LOG, args);
    
    [self executeSuccessCallback:command];
}

- (void) getSDKVersion: (CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    NSString* result = [NSString stringWithUTF8String:(getSDKVersionOnNative())];
    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:result];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

@end
