//
//  HomeViewController.swift
//  NeoSpectraSwift
//
//  Created by doda on 11/6/16.
//  Copyright © 2016 siware. All rights reserved.
//

import UIKit
import CoreBluetooth

class HomeViewController: UIViewController, NSBluetoothManagerDelegate, CBCentralManagerDelegate{
    
    let dfuServiceUUIDString  = "00001530-1212-EFDE-1523-785FEABCD123"
    let ANCSServiceUUIDString = "7905F431-B5CE-4E99-A40F-4B1E122D00D0"
    
    //MARK: - ViewController Properties
    var bluetoothManager : CBCentralManager?
    var filterUUID       : CBUUID?
    static var peripherals      : NSMutableArray?
    var timer            : Timer?
    

    @IBOutlet weak var logoConstraintY: NSLayoutConstraint!
    @IBOutlet weak var aboutConstraintY: NSLayoutConstraint!
    @IBOutlet weak var about: UITextView!
    @IBOutlet weak var deviceName: UILabel!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
    @IBOutlet weak var batteryImage: UIImageView!
    @IBOutlet weak var connectedDeviceName: UILabel!
    @IBOutlet weak var settingsButton: UIButton!
    
    @IBOutlet weak var connectButton: UIButton!
    @IBOutlet weak var disconnectButton: UIButton!
    
    //MARK: - Segue methods
    override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
        if identifier == "selectDevice"
        {
            if(self.bluetoothManager?.state == .poweredOff){
                let alertController = UIAlertController (title: "", message: "", preferredStyle: .alert)
                
                let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
                    guard let settingsUrl = URL(string: "App-Prefs:root=General") else {
                        return
                    }
                    
                    if UIApplication.shared.canOpenURL(settingsUrl) {
                        UIApplication.shared.openURL(settingsUrl)
                    }
                }
                alertController.addAction(settingsAction)
                let cancelAction = UIAlertAction(title: "OK", style: .default, handler: nil)
                alertController.addAction(cancelAction)
                let messageFont:[String : AnyObject] = [ NSFontAttributeName : UIFont.boldSystemFont(ofSize: 17.0) ]
                let attributedMessage = NSMutableAttributedString(string: "Turn On Bluetooth to Allow \"NeoSpectraMicro\" to Connect to Accessories", attributes: messageFont)
                alertController.setValue(attributedMessage, forKey: "attributedMessage")
                
                present(alertController, animated: true, completion: nil)
                return false
            }else{
                return true
            }
        }else if(identifier == "settingsView"){
            return true
        }else{
            return false
        }
    }
    
    @IBAction func disconnectButtonTapped(_ sender: Any) {
        if(disconnectButton.currentTitle == "Cancel"){
            DispatchQueue.main.async(execute: {
                self.activityIndicator.isHidden = true
                self.deviceName.isHidden = true
                self.connectedDeviceName.text = "Please Connect to a Kit"
                self.connectedDeviceName.isHidden = false
                self.connectButton.isHidden = false
                self.disconnectButton.isHidden = true
                self.initializeBluetoothManager()
                Constants.WaitToStartBluetoothConnection = true
                Constants.SelectedDeviceName = ""
                UserDefaults.standard.set("Default", forKey: "Optical_gain_settings_title")
                self.scanForPeripherals(true)
            })
            
        }else if(disconnectButton.currentTitle == "Disconnect"){
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            
            appDelegate.disconnectDevice()
        }
    }
    
    func getConnectedPeripherals() -> NSArray {
        var retreivedPeripherals : NSArray
        
        if filterUUID == nil {
            let dfuServiceUUID       = CBUUID(string: dfuServiceUUIDString)
            let ancsServiceUUID      = CBUUID(string: ANCSServiceUUIDString)
            retreivedPeripherals     = (bluetoothManager?.retrieveConnectedPeripherals(withServices: [dfuServiceUUID, ancsServiceUUID]))! as NSArray
        } else {
            retreivedPeripherals     = (bluetoothManager?.retrieveConnectedPeripherals(withServices: [filterUUID!]))! as NSArray
        }
        
        return retreivedPeripherals
    }
    
    @objc func timerFire() {
        if(Constants.WaitToStartBluetoothConnection == false){
            if (HomeViewController.peripherals?.count)! > 0 {
                DispatchQueue.main.async(execute: {
                    self.activityIndicator.isHidden = false
                    self.connectedDeviceName.isHidden = true
                    self.activityIndicator.startAnimating()
                    self.deviceName.text = "Connecting ..."
                    self.deviceName.isHidden = false
                    self.connectButton.isHidden = true
                    self.disconnectButton.setTitle("Cancel",for: .normal)
                    self.disconnectButton.isHidden = false
                })
                for peripheral in HomeViewController.peripherals!{
                    let p = peripheral as! NSScannedPeripheral
                    if(p.name() == Constants.SelectedDeviceName){
                        let appDelegate = UIApplication.shared.delegate as! AppDelegate
                        
                        appDelegate.setBlueToothManager(withManager: self.bluetoothManager!, andPeripheral: p.peripheral)
                        self.scanForPeripherals(false)
                        return
                    }
                }
            }
        }
    }
    
    /*!
     * @brief Starts scanning for peripherals with rscServiceUUID
     * @param enable If YES, this method will enable scanning for bridge devices, if NO it will stop scanning
     * @return true if success, false if Bluetooth Manager is not in CBCentralManagerStatePoweredOn state.
     */
    func scanForPeripherals(_ waitToStartConnection:Bool) -> Bool {
        guard self.bluetoothManager?.state == .poweredOn else {
            return false
        }
        DispatchQueue.main.async {
            if waitToStartConnection == true {
                let options: NSDictionary = NSDictionary(objects: [NSNumber(value: true as Bool)], forKeys: [CBCentralManagerScanOptionAllowDuplicatesKey as NSCopying])
                if self.filterUUID != nil {
                    self.bluetoothManager?.scanForPeripherals(withServices: [self.filterUUID!], options: options as? [String : AnyObject])
                } else {
                    self.bluetoothManager?.scanForPeripherals(withServices: nil, options: options as? [String : AnyObject])
                }
                self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.timerFire), userInfo: nil, repeats: true)
            } else {
                self.timer?.invalidate()
                self.timer = nil
                self.bluetoothManager?.stopScan()
            }
        }
        
        return true
    }
    
    //MARK: - ViewController
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.homeDelegate = self
        
        initializeBluetoothManager()
        
        self.connectedDeviceName.text = "Please Connect to a Kit"
        self.connectedDeviceName.sizeToFit()
        
        self.activityIndicator.isHidden = true
        self.deviceName.isHidden = true
        
        self.settingsButton.titleEdgeInsets = UIEdgeInsetsMake(10,10,10,10)
        self.connectButton.titleEdgeInsets = UIEdgeInsetsMake(10,10,10,10)
        self.disconnectButton.titleEdgeInsets = UIEdgeInsetsMake(10,10,10,10)
        self.disconnectButton.isHidden = true
        self.about.text = "Interface with NeoSpectra Micro Development Kits using your smartphone"
        //let contentSize = self.about.sizeThatFits(self.about.bounds.size)
        //var frame = self.about.frame
        //frame.size.height = contentSize.height
        //self.about.frame = frame
        
        //let aspectRatioTextViewConstraint = NSLayoutConstraint(item: self.about, attribute: .height, relatedBy: .equal, toItem: self.about, attribute: .width, multiplier: about.bounds.height/about.bounds.width, constant: 1)
        //self.about.addConstraint(aspectRatioTextViewConstraint)
        UserDefaults.standard.set("Default", forKey: "Optical_gain_settings_title")
    }
 
    func initializeBluetoothManager(){
        HomeViewController.peripherals = NSMutableArray(capacity: 8)
        
        let centralQueue = DispatchQueue(label: "no.nordicsemi.nRFToolBox", attributes: [])
        self.bluetoothManager = CBCentralManager(delegate: self, queue: centralQueue)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        NotificationCenter.default.removeObserver(self)
        if UIDevice.current.isGeneratingDeviceOrientationNotifications {
            UIDevice.current.endGeneratingDeviceOrientationNotifications()
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        if(Constants.kitInUsePSD || Constants.kitInUseSpectrum){
            self.settingsButton.isEnabled = false
        }else{
            self.settingsButton.isEnabled = true
        }
        self.deviceDidRotate()
        UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
        guard let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView else { return }
        statusBar.backgroundColor = UIColor.white
    }
    
    func deviceDidRotate(){
        if(Constants.deviceType == .iPhone6 || Constants.deviceType == .iPhone6s || Constants.deviceType == .iPhone7 || Constants.deviceType == .iPhone8){
            if(UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight){
                self.logoConstraintY.constant = 60
                self.aboutConstraintY.constant = 20
            }else if(UIDevice.current.orientation == .portrait){
                self.logoConstraintY.constant = 240
                self.aboutConstraintY.constant = 70
            }
        }else if(Constants.deviceType == .iPhone6Plus || Constants.deviceType == .iPhone6sPlus || Constants.deviceType == .iPhone7Plus || Constants.deviceType == .iPhone8Plus){
            if(UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight){
                self.logoConstraintY.constant = 80
                self.aboutConstraintY.constant = 45
            }else if(UIDevice.current.orientation == .portrait){
                self.logoConstraintY.constant = 275
                self.aboutConstraintY.constant = 105
            }
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    //MARK: - NSBluetoothManagerDelegate
    func didConnectPeripheral(deviceName aName : String)
    {
        let delayInSeconds = 3.0
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
        //DispatchQueue.main.async {
            if(Constants.WaitToStartBluetoothConnection == false){
                self.activityIndicator.isHidden = true
                self.deviceName.isHidden = true
                self.connectedDeviceName.isHidden = false
                self.activityIndicator.stopAnimating()
                let kitID = Constants.SelectedDeviceName.split(separator: "_")[1]
                self.connectedDeviceName.text = String(format: "Connected to %@" , kitID as CVarArg)
                self.disconnectButton.setTitle("Disconnect", for: .normal)
                Constants.BlueToothConnected = true
            }else{
                let appDelegate = UIApplication.shared.delegate as! AppDelegate
                
                appDelegate.disconnectDevice()
            }
        }
        
    }
    
    func didDisconnectPeripheral()
    {
        DispatchQueue.main.async(execute: {
            if(Constants.BlueToothConnected == true){
                self.connectedDeviceName.text = "Please Connect to a Kit"
                self.connectButton.isHidden = false
                self.disconnectButton.isHidden = true
                self.initializeBluetoothManager()
                Constants.WaitToStartBluetoothConnection = true
                Constants.SelectedDeviceName = ""
                UserDefaults.standard.set("Default", forKey: "Optical_gain_settings_title")
                self.scanForPeripherals(true)
            }
        })
    }
    
    func receivedDoubleData(allData:[Double], sender:AppDelegate.MainViews)
    {
    }
    
    func receivedFloatData(allData:[Float], sender:AppDelegate.MainViews)
    {
    }
    
    func reportError(error:UInt8, sender:AppDelegate.MainViews)
    {
        let alertController = UIAlertController(title: "Error", message:
            self.getErrorMessage(error: error), preferredStyle: UIAlertControllerStyle.alert)
        alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
        DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }
        
    }
    
    func getErrorMessage(error:UInt8) -> String
    {
        if(error == 101){
            return "Timeout!"
        }else if(error == 102){
            return "No background!"
        }else{
            return String(format: "Error number: %d" , error)
        }
    }
    
    //MARK: - CBCentralManagerDelgate
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        guard central.state == .poweredOn else {
            print("Bluetooth is porewed off")
            return
        }
        HomeViewController.peripherals = NSMutableArray(array: self.getConnectedPeripherals())
        self.scanForPeripherals(true)
        
    }
    
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        // Scanner uses other queue to send events. We must edit UI in the main queue
        DispatchQueue.main.async(execute: {
            var sensor = NSScannedPeripheral(withPeripheral: peripheral, andRSSI: RSSI.int32Value, andIsConnected: false)
            if ((HomeViewController.peripherals?.contains(sensor)) == false) {
                HomeViewController.peripherals?.add(sensor)
            }else{
                sensor = (HomeViewController.peripherals?.object(at: (HomeViewController.peripherals?.index(of: sensor))!))! as! NSScannedPeripheral
                sensor.RSSI = RSSI.int32Value
            }
        })
    }
}
