//
//  NewOpticalGainViewController.swift
//  NeoSpectraMicroSwift
//
//  Created by Si-Ware on 11/5/17.
//  Copyright © 2017 siware. All rights reserved.
//

import UIKit

class NewOpticalGainViewController: UIViewController , NSBluetoothManagerDelegate{
    
    @IBOutlet weak var textLabel: UILabel!
    //MARK: - View Properties
    var doubledata: [Double] = [Double]()
    var floatdata: [Float] = [Float]()
    var sender = AppDelegate.MainViews.NEWOPTICALGAIN
    var skipBoardError = 0
    var Iteration = 1
    var gainValue = UInt16(0)
    var loadingActivityIndicator: UIActivityIndicatorView!
    var viewActivityIndicator: UIView!
    var loading = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if(AppDelegate.bluetoothManager != nil && Constants.BlueToothConnected == true){
        
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            appDelegate.newOpticalGainDelegate = self
            
            //scanning view
            let width: CGFloat = 200.0
            let height: CGFloat = 50.0
            let x = self.view.frame.width/2.0 - width/2.0
            let y = self.view.frame.height/2.0 - height/2.0
            
            self.viewActivityIndicator = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
            self.viewActivityIndicator.backgroundColor = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 0.7)
            self.viewActivityIndicator.layer.cornerRadius = 10
            
            self.loadingActivityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
            self.loadingActivityIndicator.color = UIColor.white
            self.loadingActivityIndicator.hidesWhenStopped = false
            
            let titleLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
            titleLabel.text = "Scanning..."
            titleLabel.textColor = UIColor.white
            
            self.viewActivityIndicator.addSubview(self.loadingActivityIndicator)
            self.viewActivityIndicator.addSubview(titleLabel)
            
            self.textLabel.isHidden = true
        
            let setupValue = UserDefaults.standard.string(forKey: "Optical_gain_settings_title")
            if(setupValue == nil){
                UserDefaults.standard.set("Default", forKey: "Optical_gain_settings_title")
                UserDefaults.standard.synchronize()
            }
                
            let alertController = UIAlertController(title: "Check", message:
                "Please place your sample in the light path.", preferredStyle: UIAlertControllerStyle.alert)
            
            alertController.addAction(UIAlertAction(title: "Proceed", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
                self.runNewOpticalGain()
            }))
            
            alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default, handler:{ (UIAlertAction)in
                self.textLabel.isHidden = false
            }))
            
            DispatchQueue.main.async {
                self.present(alertController, animated: true, completion: nil)
            }
        }else {
            self.textLabel.text = "No NeoSpectraMicro Kit is Connected"
            self.textLabel.sizeToFit()
            self.textLabel.center = self.view.center
            self.textLabel.isHidden = false
        }
    }
    
    func runNewOpticalGain(){
        if(AppDelegate.bluetoothManager != nil && Constants.BlueToothConnected == true){
            if(self.Iteration == 1){
                if(self.loading == false){
                    self.addLoading()
                }
                let data = Data(bytes: self.setSourceSettingsBytes())
                AppDelegate.bluetoothManager?.send(data: data, sender: self.sender)
            }else{
                AppDelegate.bluetoothManager?.send(data: Constants.OPTICAL_GAIN_COMMAND , sender: self.sender)
            }
        }
    }
    
    func setSourceSettingsBytes() -> [UInt8]
    {
        //append Command
        var bytes = [UInt8]()
        bytes.append(UInt8(22))
        
        //append Source Settings Values
        let value1 = UInt32((Constants.lampSelect * 256) + Constants.lampsCount)
        let value2 = UInt32((Constants.delta_t * 256) + Constants.t1)
        let value3 = UInt32((Constants.t2_tmax * 65536) + (Constants.t2_c2 * 256) + Constants.t2_c1)
        
        let value1Bytes = self.toByteArray(value1)
        let value2Bytes = self.toByteArray(value2)
        let value3Bytes = self.toByteArray(value3)
        
        for i in 0..<4{
            bytes.append(value1Bytes[i])
        }
        
        for j in 0..<4{
            bytes.append(value2Bytes[j])
        }
        
        for k in 0..<4{
            bytes.append(value3Bytes[k])
        }
        
        return bytes
    }
    
    func toByteArray<T>(_ value: T) -> [UInt8] {
        var value = value
        return withUnsafePointer(to: &value) {
            $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
                Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
            }
        }
    }
    
    func didConnectPeripheral(deviceName aName: String) {
        
    }
    
    func didDisconnectPeripheral() {
        let alertController = UIAlertController(title: "Error", message:
            "Connection Lost.", preferredStyle: UIAlertControllerStyle.alert)
        alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
        DispatchQueue.main.async {
            self.skipBoardError = 0
            self.Iteration = 1
            if(self.loading){
                self.removeLoading()
                self.present(alertController, animated: true, completion: nil)
            }
            
        }
    }
    
    func receivedDoubleData(allData: [Double], sender: AppDelegate.MainViews) {
        self.floatdata = []
        self.doubledata = allData
        if self.doubledata.count == 1 {
            DispatchQueue.main.async {
                //if(self.skipBoardError > 0){
                //    self.skipBoardError = 0
                //}
                if(self.Iteration == 1){
                    self.Iteration = 2
                    self.runNewOpticalGain()
                }else{
                    self.removeLoading()
                    self.gainValue = UInt16(self.doubledata[0])
                    self.saveOpticalGainLogic()
                }
            }
        }
    }
    
    func receivedFloatData(allData: [Float], sender: AppDelegate.MainViews) {
        
    }
    
    func reportError(error: UInt8, sender: AppDelegate.MainViews) {
        if(self.skipBoardError < 3){
            //let delayInSeconds = 2.0
            //DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
            DispatchQueue.main.async {
                self.skipBoardError += 1
                print(self.skipBoardError)
                self.Iteration = 1
                self.runNewOpticalGain()
            }
        }else{
            let alertController = UIAlertController(title: "Error", message:
                self.getErrorMessage(error: error), preferredStyle: UIAlertControllerStyle.alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
            let delayInSeconds = 2.0
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
                //DispatchQueue.main.async {
                if(self.skipBoardError > 0){
                    self.skipBoardError = 0
                }
                self.Iteration = 1
                if(self.loading)
                {
                    self.removeLoading()
                    self.textLabel.isHidden = false
                }
                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)
        }
    }
    
    func saveOpticalGainLogic(){
        let alertController = UIAlertController(title: "Save Optical Gain Settings", message:
            "Please enter a unique name for this optical gain setting.", preferredStyle: UIAlertControllerStyle.alert)
        alertController.addTextField { (configurationTextField) in
            //configure here your textfield
            configurationTextField.textColor = UIColor.black
            configurationTextField.keyboardType = UIKeyboardType.namePhonePad
        }
        
        alertController.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
            let textField = (alertController.textFields?.first)! as UITextField
            if(textField.text == "") {
                self.showEmptyNameError()
            }else if(textField.text?.caseInsensitiveCompare("default") == ComparisonResult.orderedSame){
                self.showDefaultOverwriteError()
            } else if(self.nameAlreadyExists(setupName: textField.text!)){
                self.showNameAlreadyExistsWarning(setupName: textField.text!, setupValue: self.gainValue)
            }else{
                self.saveOpticalGainValue(setupName: textField.text!, setupValue: self.gainValue)
            }
        }))
        
        alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default, handler:{ (UIAlertAction)in
            self.textLabel.isHidden = false
        }))
        
        DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    func saveOpticalGainValue(setupName: String, setupValue: UInt16){
        let kitID = Constants.SelectedDeviceName.components(separatedBy: "_")[1]
        if(UserDefaults.standard.object(forKey: "Optical_gain_settings_options") != nil){
            var currentOptions = UserDefaults.standard.object(forKey: "Optical_gain_settings_options") as! [String : String]
            if let result  = currentOptions.first(where: {(key, _) in key.range(of: setupName + "_" + kitID, options: .caseInsensitive) != nil}) {
                currentOptions.removeValue(forKey: result.key)
            }
            currentOptions[setupName + "_" + kitID] =  String(setupValue)
            
            UserDefaults.standard.removeObject(forKey: "Optical_gain_settings_options")
            UserDefaults.standard.set(currentOptions, forKey: "Optical_gain_settings_options")
            UserDefaults.standard.synchronize()
            
        }else{
            let newOptions = ["Default" : "0" , setupName + "_" + kitID : String(setupValue)]
            UserDefaults.standard.set(newOptions, forKey: "Optical_gain_settings_options")
            UserDefaults.standard.synchronize()
        }
        UserDefaults.standard.set(setupName, forKey: "Optical_gain_settings_title")
        UserDefaults.standard.synchronize()
        
        self.textLabel.text = "New Optical Settings Added"
        self.textLabel.sizeToFit()
        self.textLabel.center = self.view.center
        self.textLabel.isHidden = false
    }
    
    func showNameAlreadyExistsWarning(setupName: String, setupValue: UInt16){
        let alertController = UIAlertController(title: "Name Already Exists", message:
            "Another gain settings’ file has the same name. Do you want to overwrite it ?", preferredStyle: UIAlertControllerStyle.alert)
        
        
        alertController.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
            self.saveOpticalGainValue(setupName: setupName, setupValue: setupValue)
        }))
        
        alertController.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
            self.saveOpticalGainLogic()
        }))
        
        DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    func showDefaultOverwriteError(){
        let alertController = UIAlertController(title: "Error", message:
        "Default name can’t be overwritten.", preferredStyle: UIAlertControllerStyle.alert)
        
        alertController.addAction(UIAlertAction(title: "Change name", style: UIAlertActionStyle.default, handler:{ (UIAlertAction)in
            self.saveOpticalGainLogic()
        }))
        
        DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    func showEmptyNameError(){
        let alertController = UIAlertController(title: "Error", message:
            "Gain settings name can’t be empty.", preferredStyle: UIAlertControllerStyle.alert)
        
        
        alertController.addAction(UIAlertAction(title: "Enter name", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
            self.saveOpticalGainLogic()
        }))
        
        DispatchQueue.main.async {
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    func nameAlreadyExists(setupName: String)-> Bool{
        if(UserDefaults.standard.object(forKey: "Optical_gain_settings_options") != nil){
            let kitID = Constants.SelectedDeviceName.components(separatedBy: "_")[1]
            let currentSetupOptions = UserDefaults.standard.object(forKey: "Optical_gain_settings_options") as! [String : String]
            if currentSetupOptions.first(where: {(key, _) in key.range(of: setupName + "_" + kitID, options: .caseInsensitive) != nil}) != nil{
                return true
            }else{
                return false
            }
        }else{
            return false
        }
    }
    
    //MARK: ViewLoading
    func removeLoading() -> Void {
        self.loading = false
        self.loadingActivityIndicator.stopAnimating()
        UIApplication.shared.endIgnoringInteractionEvents()
        self.viewActivityIndicator.removeFromSuperview()
    }
    
    func addLoading() -> Void {
        self.view.addSubview(self.viewActivityIndicator)
        self.loadingActivityIndicator.startAnimating()
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.loading = true
        self.skipBoardError = 0
    }
    
}
