#if OBJC
#import <CommonCrypto/CommonHMAC.h>

- (NSData*) hmacForKeyAndData:(NSData*)cKey :(NSData*) cData
{
  unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
  CCHmac(kCCHmacAlgSHA256, [cKey bytes], [cKey length], [cData bytes], [cData length], cHMAC);
  return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
#End If



#If OBJC

#import <SystemConfiguration/CaptiveNetwork.h>

- (NSString *)currentWifiSSID {
  // Does not work on the simulator.
  NSString *ssid = nil;
  NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
  for (NSString *ifnam in ifs) {
  NSDictionary *info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
  if (info[@"SSID"]) {
  ssid = info[@"SSID"];
  }
  }
  return ssid;
}
#end if


#If OBJC
#import <UserNotifications/UserNotifications.h>
- (BOOL)isRegisteredForRemoteNotifications {
    if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]) return YES;
    return NO;
}

- (BOOL)pushNotificationsEnabled {
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(currentUserNotificationSettings)]) {
        UIUserNotificationType types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
        return (types & UIUserNotificationTypeAlert);
    }
    else {
        UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
       return (types & UIUserNotificationTypeAlert);
    }
}
#end if

#AdditionalLib: UserNotifications.framework
#if OBJC
#import <UserNotifications/UserNotifications.h>
@end
@interface b4i_main (notification) <UNUserNotificationCenterDelegate>
@end
@implementation b4i_main (notification)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler {
       B4I* bi = [b4i_main new].bi;
[bi raiseEvent:nil event:@"usernotification_action:" params:@[response]];
completionHandler();
   }
#End If


#If OBJC
@end
#import <objc/runtime.h>
@interface UINavigationController (SM)
@property (nonatomic, readwrite, strong) NSObject * myPrefersStatusBarHidden;
@property (nonatomic, readwrite, strong) NSObject * myPrefersLightStatusBar;
@end
@implementation UINavigationController (SM)
- (NSObject *) myPrefersStatusBarHidden { return objc_getAssociatedObject (self, @selector (myPrefersStatusBarHidden)); }
- (void) setMyPrefersStatusBarHidden: (NSObject *) value { objc_setAssociatedObject (self, @selector (myPrefersStatusBarHidden), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
- (NSObject *) myPrefersLightStatusBar  { return objc_getAssociatedObject (self, @selector (myPrefersLightStatusBar)); }
- (void) setMyPrefersLightStatusBar:  (NSObject *) value { objc_setAssociatedObject (self, @selector (myPrefersLightStatusBar),  value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }

- (BOOL) prefersStatusBarHidden { NSNumber * value = self.myPrefersStatusBarHidden; return value.boolValue; }

- (UIStatusBarStyle) preferredStatusBarStyle { NSNumber * value = self.myPrefersLightStatusBar; 
if (@available (iOS 13, *)) { return value.boolValue ? UIStatusBarStyleLightContent : UIStatusBarStyleDarkContent; }
					else    { return value.boolValue ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault; }; }	

// Do not redirect to ViewControllers					
- (UIViewController*) childViewControllerForStatusBarHidden { return nil; }
- (UIViewController*) childViewControllerForStatusBarStyle  { return nil; }
#End If

#if OBJC
@end
@implementation B4IAppDelegate (register1)

-(void) application:(UIApplication *)application  didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    B4I* bi = [b4i_main new].bi;
    [bi raiseUIEvent:nil event:@"application_register:" params:@[notificationSettings]];
}
#End If

#if OBJC
@end
@interface UINavigationController (SM)
@end
@implementation UINavigationController (SM)
- (BOOL) shouldAutorotate
    {
    NSDictionary* map1    = [B4IObjectWrapper getMap: self];
    NSDictionary* map2    = map1 [@"tag"];
    NSNumber*     number  = map2 [@"shouldAutorotate"];
    return number.boolValue;
    }

- (BOOL) prefersStatusBarHidden             
   {
   NSDictionary* map1 = [B4IObjectWrapper getMap: self]; 
   NSDictionary* map2 = map1 [@"tag"];        
   NSNumber* number = map2 [@"prefersStatusBarHidden"];   
   return number.boolValue; 
   }
   
- (UIStatusBarStyle) preferredStatusBarStyle 
   {   
   NSDictionary* map1   = [B4IObjectWrapper getMap: self]; 
   NSDictionary* map2   = map1 [@"tag"];
   NSNumber*     number = map2 [@"prefersLightStatusBarStyle"];   
   if (@available (iOS 13, *))
       { if (number.boolValue) { return UIStatusBarStyleLightContent; } else { return UIStatusBarStyleDarkContent; }; }
   else
	   { if (number.boolValue) { return UIStatusBarStyleLightContent; } else { return UIStatusBarStyleDefault; }; };    
   }

//  Theoretically not needed
- (UIViewController *) childViewControllerForStatusBarHidden { return nil; }
- (UIViewController *) childViewControllerForStatusBarStyle { return nil; }
#End If


'CLV SWIPE
#if OBJC
- (NSObject*) CreateRecognizer{
 	 UIPanGestureRecognizer *rec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(action:)];
    [rec setMinimumNumberOfTouches:1];
    [rec setMaximumNumberOfTouches:1];
	return rec;
}
-(void) action:(UIPanGestureRecognizer*)rec {
	[self.bi raiseEvent:nil event:@"pan_event:" params:@[rec]];
}
#End If


'GESTURE RECOGNIZER

#If OBJC

/////////TAP//////////

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
     return TRUE;
}

-(void)grTap: (int)numtaps :(int)numtouch :(UIView*)v
{
UITapGestureRecognizer *Tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
Tap.delegate=self;
[Tap setNumberOfTapsRequired:numtaps];
[Tap setNumberOfTouchesRequired:numtouch];


[v addGestureRecognizer:Tap];
}

- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer {  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;


	int st =gestureRecognizer.state;
    int numtouch =gestureRecognizer.numberOfTouchesRequired;
    int numtap =gestureRecognizer.numberOfTapsRequired;
    [self.bi raiseEvent:nil event:@"uigesture_tap::::::" params:@[@((int)st),@((int)numtap),@((int)numtouch),@((float)x),@((float)y),(gestureRecognizer)]];

  }  


////////////PINCH/////////////

-(void)grPinch :(UIView*)v
{
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self  action:@selector(handlePinch:)];
 pinch.delegate=self;
 [v addGestureRecognizer:pinch];

}

- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer 
{  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

	float sc=gestureRecognizer.scale;
	float vl=gestureRecognizer.velocity;
	int st =gestureRecognizer.state;
    [self.bi raiseEvent:nil event:@"uigesture_pinch::::::" params:@[@((float)sc),@((float)vl),@((int)st),@((float)x),@((float)y),(gestureRecognizer)]];


  }  
  

  
  
//////// ROTATION /////////////

-(void)grRotation :(UIView*)v
{
UIRotationGestureRecognizer *Rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self  action:@selector(handleRotation:)];
 Rotation.delegate=self;
 [v addGestureRecognizer:Rotation];

}

- (void)handleRotation:(UIRotationGestureRecognizer *)gestureRecognizer 
{  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

	float rt=gestureRecognizer.rotation;
	float vl=gestureRecognizer.velocity;
	int st =gestureRecognizer.state;
    [self.bi raiseEvent:nil event:@"uigesture_rotation::::::" params:@[@((float)rt),@((float)vl),@((int)st),@((float)x),@((float)y),(gestureRecognizer)]];


  }  
  
  
///////////// SWIPE //////////////

-(void)grSwipe :(UIView*)v :(int)numtouch :(int)dir
{
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self  action:@selector(handleSwipe:)];
 
// if (dir==1)
// {
  [swipe setDirection:dir];

// }
 
 
 [swipe setNumberOfTouchesRequired:numtouch];
  swipe.delegate=self;
 [v addGestureRecognizer:swipe];

}


- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer {  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

	int st =gestureRecognizer.state;
	int dir=gestureRecognizer.direction;

    [self.bi raiseEvent:nil event:@"uigesture_swipe:::::" params:@[@((int)st),@((int)dir),@((float)x),@((float)y),(gestureRecognizer)]];

  }  

/////////// PAN ///////////

-(void)grPan :(UIView*)v :(int)mintouch :(int)maxtouch
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self  action:@selector(handlePan:)];
 
 [pan setMaximumNumberOfTouches:maxtouch];
 [pan setMinimumNumberOfTouches:mintouch];
pan.delegate=self;
 [v addGestureRecognizer:pan];

}

- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer {  

	int st =gestureRecognizer.state;
float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

    [self.bi raiseEvent:nil event:@"uigesture_pan::::" params:@[@((int)st),@((float)x),@((float)y),(gestureRecognizer)]];

  }  

///////////// SCREEN EDGE ///////////

-(void)grScreenEdge :(UIView*)v :(int)dir 
{
UIScreenEdgePanGestureRecognizer *panEdge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self  action:@selector(handlePanEdge:)];
 
 [panEdge setEdges:dir];
 [v addGestureRecognizer:panEdge];

}

- (void)handlePanEdge:(UIScreenEdgePanGestureRecognizer *)gestureRecognizer {  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

	int st =gestureRecognizer.state;
	int ed =[gestureRecognizer edges];
    [self.bi raiseEvent:nil event:@"uigesture_screenedgepan:::::" params:@[@((int)st),@((int)ed),@((float)x),@((float)y),(gestureRecognizer)]];

  }  
  
  
  
///////////LONG PRESS////////


-(void)grLongPress: (int)numtaps :(int)numtouch :(float)interval :(UIView*)v
{
UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];

[longpress setNumberOfTapsRequired:numtaps];
[longpress setNumberOfTouchesRequired:numtouch];
[longpress setMinimumPressDuration:interval];
longpress.delegate=self;
[v addGestureRecognizer:longpress];
}

- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer {  

float x= [gestureRecognizer locationInView:(self._mview).object].x;
float y= [gestureRecognizer locationInView:(self._mview).object].y;

	int st =gestureRecognizer.state;
	int numtouch =gestureRecognizer.numberOfTouchesRequired;
    int numtap =gestureRecognizer.numberOfTapsRequired;
    [self.bi raiseEvent:nil event:@"uigesture_longpress::::::" params:@[@((int)st),@((int)numtouch),@((int)numtap),@((float)x),@((float)y),(gestureRecognizer)]];
  }  

#End If



'Text Recognizer
#if OBJC
-(void (^)(id, id)) createBlock {
	void (^block)(id result, id error) = ^void (id result, id error){
		if (error != nil || result == nil) {
			[B4I shared].lastError = error;
			[self.bi raiseUIEvent:nil event:@"process_result::" params:@[@(false), [NSNull null]]];
		} else {
			[self.bi raiseUIEvent:nil event:@"process_result::" params:@[@(true), result]];
		}
	};
	return block;
}
#End If


#if OBJC
#import <UserNotifications/UserNotifications.h>
@end
@interface b4i_usernotificationcenter (notification) <UNUserNotificationCenterDelegate>
@end
@implementation b4i_usernotificationcenter (notification)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
        completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound );
   }
 - (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler {
       B4I* bi = [b4i_main new].bi;
[bi raiseEvent:nil event:@"usernotification_action:" params:@[response]];
completionHandler();
   }
#End If


xPhoneSensors

#if OBJC

- (void)startMotion:(CMMotionManager*)manager {
   [manager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXArbitraryCorrectedZVertical];
}

- (NSArray*) getAcceleration: (CMMotionManager*) manager {
	CMDeviceMotion *motion = manager.deviceMotion;
	CMAcceleration acc = motion.userAcceleration;
	return @[@(acc.x), @(acc.y), @(acc.z)];
}

- (NSArray*) getGravity: (CMMotionManager*) manager {
	CMDeviceMotion *motion = manager.deviceMotion;
	CMAcceleration grv = motion.gravity;
	return @[@(grv.x), @(grv.y), @(grv.z)];
}

- (NSArray*) getGyro: (CMMotionManager*) manager {
	CMDeviceMotion *motion = manager.deviceMotion;
	CMRotationRate gyr = motion.rotationRate;
	return @[@(gyr.x), @(gyr.y), @(gyr.z)];
}

- (NSArray*) getMagField: (CMMotionManager*) manager {
	CMDeviceMotion *motion = manager.deviceMotion;
	CMCalibratedMagneticField magfld = motion.magneticField;
	return @[@(magfld.field.x), @(magfld.field.y), @(magfld.field.z)];
	
}

- (NSArray*) getMagAccuracy: (CMMotionManager*) manager {
	CMDeviceMotion *motion = manager.deviceMotion;
	CMCalibratedMagneticField magfld = motion.magneticField;
	return @[@(magfld.accuracy)];
	
}
#end if
