//
//  NetworkServiceHandler.m
//  OneCable
//
//  Created by Jason Lee on 2/15/16.
//  Copyright © 2016 ntels. All rights reserved.
//
#import "JDObject.h"
#import "NetworkServiceHandler.h"
#import "Reachability.h"
#import "NSString-Addtions.h"
#import "NSNetService+Util.h"


@interface NetworkServiceHandler () <NSNetServiceBrowserDelegate, NSNetServiceDelegate>
{
    NSNetServiceBrowser *_netServiceBrowser;
    BOOL _isNotFirstLoading;
    Reachability *_reachability;
    
    NSMutableArray* _services;
}

@property (strong, nonatomic)  NSNetService *netService;

@end

@implementation NetworkServiceHandler


- (BOOL)startSearchBonjourServices {
    NSLog(@"currentReachabilityStatus= %zd", _reachability.currentReachabilityStatus);
    
//    _isNotFirstLoading = NO;
    if (_reachability.currentReachabilityStatus != ReachableViaWiFi) {
        return NO;
    }
    
    //1.check if wifi
//    if (_netServiceBrowser) {
//        [_netServiceBrowser stop];
//        _netServiceBrowser = nil;
//    }
    
    NSString *browseType;
    if (!_netService) {
        _netServiceBrowser = [[NSNetServiceBrowser alloc] init];
        _netServiceBrowser.delegate = self;
        _services = [[NSMutableArray alloc] init];
        
//        browseType = @"_services._dns-sd._udp.";
        browseType = @"_ntelshub._tcp.";
//        browseType = @"_ntelshub._tcp.local.";
        NSLog(@"Serch BrowseType : %@", browseType);
        [_netServiceBrowser searchForServicesOfType:browseType inDomain:@""];
    } else {
        [self publishNetService];

    }
    
    return YES;
}

- (void)stopSearchBonjourServices{
    if (_netServiceBrowser) {
        [_netServiceBrowser stop];
        _netServiceBrowser = nil;
    }
    
    if(_netService) {
        [_netService stop];
        _netService = nil;
    }
}

- (void)publishNetService {
    NSLog(@"%@", [JDFacade facade].deviceHostName);

    if (!_netService) {
        _netService = [[NSNetService alloc] initWithDomain:@"" type:@"_ntelshub._tcp" name:[JDFacade facade].deviceHostName port:7979];
        _netService.delegate = self;
    }
    
    if (_netService) {
        [_netService publish];
        
    } else {
        NSLog(@"An error occurred initializing the NSNetService object.");
    }
}


#pragma mark - NSNetServiceDelegate methods

- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
/*
 현재 안드로이드에서 MDNS통해서 수집하는 정보는 manufacturer, modelNumber, serialNumber, profileVersion, hostAddress 입니다.
 
 */
    [service setDelegate:self];
    [service resolveWithTimeout:0.0];
    [_services addObject:service];

//    NSMutableDictionary *info = [NSMutableDictionary dictionary];
//    NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[service TXTRecordData]];
//    info[@"name"] = service.name;
//    info[@"domain"] = service.domain;
//    info[@"type"] = service.type;
//    info[@"hostName"] = service.hostName;
//    info[@"Data"] = service.type;
//    info[@"Address"] = service.addresses;
////    info[@"port"] = service.port;
//        NSLog(@"Finish :  %@", info   );
//    NSLog(@"Info :  %@", dict   );
//
//    if (!moreComing)
//    {
//        [self chkServiceData];
//    }
//    
    if (!_isNotFirstLoading) {
        [self publishNetService];
        _isNotFirstLoading = YES;
    }
}

-(void)chkServiceData
{
    for (NSNetService *service in _services)
    {
        NSMutableDictionary *info = [NSMutableDictionary dictionary];
            info[@"name"] = service.name;
            info[@"domain"] = service.domain;
            info[@"type"] = service.type;
            info[@"hostName"] = service.hostName;
            info[@"Data"] = service.type;
            info[@"Address"] = service.addresses;
        NSLog(@"Service :  %@", info   );
        
        NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[service TXTRecordData]];
        NSLog(@"Service TXT :  %@", dict   );
    }
}

- (void)netServiceDidPublish:(NSNetService *)sender {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, sender);
    
//    if (self.delegate && [self.delegate respondsToSelector:@selector(didSucceedPublishService)]) {
//        [self.delegate didSucceedPublishService];
//    }
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(didSucceedPublishService:)]) {
        [self.delegate didSucceedPublishService:_services];
    }
}

- (void)netServiceWillPublish:(NSNetService *)sender {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, sender);
    
}

- (void)netServiceDidStop:(NSNetService *)sender {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, sender);
    
}

- (void)netService:(NSNetService *)sender didAcceptConnectionWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, sender);
    
}

- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary<NSString *,NSNumber *> *)errorDict {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, errorDict);
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(didFailPublishService:)]) {
        [self.delegate didFailPublishService:errorDict];
    }
}

- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
    NSLog(@"%s\n %@", __PRETTY_FUNCTION__, sender);
    NSNumber *errorCode = [errorDict valueForKey:NSNetServicesErrorCode];
    
    switch ([errorCode intValue]) {
        case NSNetServicesActivityInProgress:
            NSLog(@"%s\n %@", __PRETTY_FUNCTION__, @"Service Resolution Currently in Progress. Please Wait.");
            break;
        case NSNetServicesTimeoutError:
            NSLog(@"%s\n %@", __PRETTY_FUNCTION__, @"Service Resolution Currently in Progress. Please Wait.");
            
            //service stop
            [sender stop];
            
            if (self.delegate && [self.delegate respondsToSelector:@selector(didFailPublishService:)]) {
                [self.delegate didFailPublishService:errorDict];
            }
            
            break;
    }
}

- (void)netServiceDidResolveAddress:(NSNetService *)service
{
    NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:[service TXTRecordData]];
    /*
     manufacturer = <4e54656c 73>;
     "model_number" = <53544248 55427633>;
     "profile_version" = <7633>;
     "serial_number" = <30383632 36363064 30633935>;
     */
    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    info[@"name"] = service.name;
    info[@"domain"] = service.domain;
    info[@"type"] = service.type;
    info[@"hostName"] = service.hostName;
    info[@"Data"] = service.type;
//    info[@"Address"] = service.addressesAndPorts;
    
    for (AddressAndPort *addrInfo in service.addressesAndPorts) {
        NSLog(@"ADDR : %@", addrInfo.address);
    }
    

    
    for (NSString *key in dict.allKeys) NSLog(@"[%@] : %@", key,[NSString stringWithUTF8Data:[dict objectForKey:key]]);

}


#pragma mark - Reachability Notification
- (void)netReachabilityChanged:(id)notification {
    
    if (_reachability.currentReachabilityStatus == ReachableViaWiFi) {
        NSLog(@"%s\n currentReachabilityStatus = %zd", __PRETTY_FUNCTION__, _reachability.currentReachabilityStatus);
        [self performSelectorInBackground:@selector(startSearchBonjourServices) withObject:nil];
    }
}

- (void)dealloc {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:kReachabilityChangedNotification];
    
    [_reachability stopNotifier];
    [_netServiceBrowser stop];
}


#pragma mark - Singleton

+ (NetworkServiceHandler *)handler {
    
    static NetworkServiceHandler *sharedNetworkServiceHandler = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedNetworkServiceHandler = [[self alloc] init];
    });
    return sharedNetworkServiceHandler;
}

- (id)init {
    if (self = [super init]) {
        
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(netReachabilityChanged:) name:kReachabilityChangedNotification object:nil];
        
        _reachability = [Reachability reachabilityForLocalWiFi];
        [_reachability startNotifier];
    }
    return self;
}


@end
