//
//  PrinterListViewController.m
//  SiiLibSample
//

#import "PrinterListViewController.h"
#import <ExternalAccessory/ExternalAccessory.h>
#import "SampleValue.h"
#import "SampleFunctions.h"

@interface PrinterListViewController ()<UITableViewDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UIView *printerListLoadingView;
@end

@implementation PrinterListViewController {
    NSArray *_tableData;
    dispatch_queue_t _gcd_printerDiscoverQueue;
    BOOL _discoverComplete;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.tableView.delegate = (id <UITableViewDelegate>)self;
    self.tableView.dataSource = (id <UITableViewDataSource>)self;
    _gcd_printerDiscoverQueue = dispatch_queue_create("com.sii-ps.printerDiscover", DISPATCH_QUEUE_SERIAL);
    self.printer = [[SiiPrinter alloc] init];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self cancelDiscoveryTcpPrinter];
}

- (void)viewDidAppear:(BOOL)animated {
    [self searchPrinter];
}

- (IBAction)onRefreshPrinterListButtonTouched:(id)sender {
    _tableData = nil;
    [self searchPrinter];
}

- (IBAction)onClosePrinterListViewButtonTouched:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)onLoadingViewCancelButtonTouched:(id)sender {
    [self hidePrinterListLoadingView];
    [self cancelDiscoveryTcpPrinter];
}

- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"PrinterListViewCell";
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    SiiPrinter *printer = [_tableData objectAtIndex:indexPath.row];
    cell.textLabel.text = [NSString stringWithFormat:@"%@", printer.address];
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@  %@",  printer.portType, printer.seriesName];
    cell.accessoryType = UITableViewCellAccessoryNone;
    return cell;
}

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return _tableData.count;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    self.printer = _tableData[indexPath.row];
    // Back to main view
    [self performSegueWithIdentifier:@"return" sender:self];
}

/// Printer discovery process
- (void)searchPrinter {
    [self showPrinterListLoadingView];
    dispatch_async(_gcd_printerDiscoverQueue, ^{
        self->_tableData = [[NSMutableArray alloc] init];
        [self searchBluetoothPrinter];
        [self searchTcpPrinter];
        [self hidePrinterListLoadingView];
    });
}

/// Bluetooth printer discovery process
- (void)searchBluetoothPrinter {
    NSMutableArray<SiiPrinter *> *printerList = [[NSMutableArray alloc] init];
    // Get accessories that connecting with current iOS device from EAAccessoryManager
    NSArray *accessories = [[EAAccessoryManager sharedAccessoryManager] connectedAccessories];
    if (accessories != nil && accessories.count > 0) {
        for (EAAccessory *obj in accessories) {
            // Get SII devices from all connected accessories
            if ([[obj protocolStrings] containsObject:SII_EXTERNAL_ACCESSORY_PROTOCOL] == YES) {
                SiiPrinter *printer = [[SiiPrinter alloc] init];
                // Determine connect type from device's macAddress:
                // Mac address can be get: bluetooth device
                // Mac address can not be get: USB device
                NSString *macAddress = [obj valueForKey:@"macAddress"];
                if (macAddress.length > 0) {
                    printer.type = SII_PM_PRINTER_PORT_TYPE_BLUETOOTH;
                } else {
                    printer.type = SII_PM_PRINTER_PORT_TYPE_USB;
                }
                // Set accessorie's name as printer address
                printer.address = obj.name;
                // Get printer's type number from port type
                printer.portType = [printer getPrinterPortType:printer.type];
                // Set printer's series name
                printer.seriesName = obj.modelNumber;
                // Get printer's model name from series name
                printer.modelName = [printer getPrinterModelName:printer.seriesName];
                // Get printer's model number from model name
                printer.model = [printer getPrinterModel:printer.modelName];
                // Add current printer to printer list
                [printerList addObject:printer];
            }
        }
        self->_tableData = printerList;
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    }
}

/// Tcp printer discovery process
- (void)searchTcpPrinter {
    NSMutableArray<SiiPrinter *> *printerList = [[NSMutableArray alloc] init];
    NSMutableArray<SIIPrinterInfo *> *tcpPrinterList = [[NSMutableArray alloc] init];
    [self startDiscoveryTcpPrinter];
    // Repeat process until discovery completed
    while ([SampleFunctions getPrinterDiscoveryCompletion] == NO) {
        // Copy from previous founded printer list
        if (self->_tableData.count > 0) {
            printerList = self->_tableData.mutableCopy;
        }
        NSArray *lanPrinterlist = [SampleFunctions getFoundPrinterSample];
        tcpPrinterList = [NSMutableArray arrayWithArray:lanPrinterlist];
        
        if (tcpPrinterList != nil && tcpPrinterList.count > 0) {
            for (int i = 0; i < tcpPrinterList.count; i++) {
                SIIPrinterInfo *obj = [tcpPrinterList objectAtIndex:i];
                SiiPrinter *printer = [[SiiPrinter alloc] init];
                // Set ip as printer's address
                printer.address = obj.ip;
                // Set printer's port type number as TCP and get port type name from port type
                printer.type = SII_PM_PRINTER_PORT_TYPE_TCP;
                printer.portType = [printer getPrinterPortType:printer.type];
                
                // Set printer's series name
                printer.seriesName = obj.name;
                // Get printer's model name from series name
                printer.modelName = [printer getPrinterModelName:printer.seriesName];
                // Get printer's model number from model name
                printer.model = [printer getPrinterModel:printer.modelName];
                
                // Determine whether current printer is existed in previous founded printer list
                BOOL isPrinterExist = false;
                for (int j = 0; j < printerList.count; j++) {
                    SiiPrinter *existPrinter = [printerList objectAtIndex:j];
                    if ([printer.address isEqualToString:existPrinter.address]) {
                        isPrinterExist = true;
                        break;
                    }
                }
                // Add current printer to printer list if it is not in precious founded list
                if (isPrinterExist == false) {
                    [printerList addObject:printer];
                    self->_tableData = printerList;
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.tableView reloadData];
                    });
                }
            }
        }
        [NSThread sleepForTimeInterval:0.01];
    }
}

/// Start lan printer discovery process
- (void)startDiscoveryTcpPrinter {
    [SampleFunctions startLanDiscoveryPrinterSample:1 timeout:10000];
}

/// Cancel current discovery process immediately
- (void)cancelDiscoveryTcpPrinter {
    [SampleFunctions cancelDiscoveryPrinterSample];
}

- (void)showPrinterListLoadingView {
    dispatch_async(dispatch_get_main_queue(), ^{
        self->_printerListLoadingView.hidden = NO;
    });
}

- (void)hidePrinterListLoadingView {
    dispatch_async(dispatch_get_main_queue(), ^{
        self->_printerListLoadingView.hidden = YES;
    });
}

@end
