//
//  PSDViewController.swift
//  NeoSpectraSwift
//
//  Created by doda on 10/26/16.
//  Copyright © 2016 siware. All rights reserved.
//

import UIKit
import CoreBluetooth

class PSDViewController: UIViewController ,NSBluetoothManagerDelegate  {
    
    //MARK: - View Properties
    var doubledata: [[Double]] = [[Double]]()
    var floatdata: [Float] = [Float]()
    var buttonAnimating = false
    var sender = AppDelegate.MainViews.PSD
    var skipBoardError = 0
    var Iteration = 1
    var requestedMode = 0
    
    //MARK: - View OUtlets
    @IBOutlet weak var scanTimeConstraint: NSLayoutConstraint!
    @IBOutlet weak var scanViewConstraint: NSLayoutConstraint!
    @IBOutlet weak var scanTimeTF: UITextField!
    @IBOutlet weak var showRawDataButton: UIButton!
    @IBOutlet weak var loadPSDButton: UIButton!
    @IBOutlet weak var scanButton: UIButton!
    @IBOutlet weak var stopButton: UIButton!
    
    @IBAction func loadPSDButtonTapped(_ sender: Any) {
        let fileBrowser = FileBrowser(save_load: "load")
        fileBrowser.excludesFileExtensions = ["Spectrum"]
        fileBrowser.setPSDView(PSDView: self)
        present(fileBrowser, animated: true, completion: nil)
    }
    @IBAction func stopButtonTapped(_ sender: Any) {
        self.requestedMode = 0
    }
    @IBAction func buttonTapped(_ sender: AnyObject){
        if(Constants.kitInUsePSD == false){
            self.dismissKeyboard()
            if(isValidData()){
                if(UserDefaults.standard.integer(forKey: "Run_mode") == 0){
                    self.requestedMode = 0
                }else{
                    self.requestedMode = 1
                }
                self.runPSD()
            }
        }
    }
    
    func loadDataLogic(dataPaths: [URL]){
        for i in 0..<dataPaths.count{
            var textofFile = ""
            do {
                textofFile = try String(contentsOf: dataPaths[i], encoding: .utf8)
            }
            catch {/* error handling here */}
            var textLines = textofFile.split(separator: "\n")
            let xAxisUnit = textLines[0].split(separator: "\t")[0]
            textLines.removeFirst()
            var data = [Double]()
            var x = [Double] ()
            var y = [Double] ()
            for j in 0..<textLines.count{
                if(xAxisUnit == "x_Axis:Wavenumber (cm-1)"){
                    y.append(Double(textLines[j].split(separator: "\t")[1])!)
                    x.append(Double(textLines[j].split(separator: "\t")[0])!)
                }else{
                    y.insert(Double(textLines[j].split(separator: "\t")[1])!, at: 0)
                    x.insert(10000000/(Double(textLines[j].split(separator: "\t")[0])!), at: 0)
                }
            }
            data = y + x
            Constants.PSDdoubledata.append(data)
        }
    }
    
    func runPSD(){
        if(AppDelegate.bluetoothManager != nil && Constants.BlueToothConnected == true){
            if(self.Iteration == 1){
                if(self.buttonAnimating == false){
                    self.startScanButtonAnimation()
                }
                let data = Data(bytes: self.setOpticalGainBytes())
                AppDelegate.bluetoothManager?.send(data: data, sender: self.sender)
            }else if(self.Iteration == 2){
                let data = Data(bytes: self.setSourceSettingsBytes())
                AppDelegate.bluetoothManager?.send(data: data, sender: self.sender)
            }else{
                let data = Data(bytes: self.getRunBytes(command: 0x03))
                AppDelegate.bluetoothManager?.send(data: data, sender: self.sender)
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.psdDelegate = self
        //self.showRawDataButton.isHidden = true
        self.stopButton.isHidden = true
        self.showRawDataButton.titleEdgeInsets = UIEdgeInsetsMake(10,10,10,10)
        self.loadPSDButton.titleEdgeInsets = UIEdgeInsetsMake(10,10,10,10)
        if(Constants.BlueToothConnected == false){
            self.scanButton.isEnabled = false
        }
        //keyboard gesture
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(PSDViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
    }
    
    func dismissKeyboard() {
        view.endEditing(true)
    }
    
    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 setOpticalGainBytes() -> [UInt8]
    {
        //append Command
        var bytes = [UInt8]()
        bytes.append(UInt8(27))
        
        //append Optical Settings Value
        let selectedOption = UserDefaults.standard.string(forKey: "Optical_gain_settings_title")
        if(selectedOption != nil){
            if(UserDefaults.standard.object(forKey: "Optical_gain_settings_options") != nil){
                let kitID = Constants.SelectedDeviceName.components(separatedBy: "_")[1]
                let currentOptions = UserDefaults.standard.object(forKey: "Optical_gain_settings_options") as! [String : String]
                var selectedValue = ""
                if(selectedOption == "Default"){
                    selectedValue = currentOptions[selectedOption!]!
                }else{
                    selectedValue = currentOptions[selectedOption! + "_" + kitID]!
                }
                let value = UInt16(selectedValue)
                let Valuebytes = self.toByteArray(value)
                bytes.append(Valuebytes[0])
                bytes.append(Valuebytes[1])
            }else{
                bytes.append(UInt8(0))
                bytes.append(UInt8(0))
            }
        }else{
            bytes.append(UInt8(0))
            bytes.append(UInt8(0))
        }
        
        return bytes
    }
    
    func getRunBytes(command: UInt8) -> [UInt8]
    {
        var bytes = [UInt8]()
        bytes.append(command)
        let st  = Int(Double(scanTimeTF.text!)! * 1000)
        let scan_time = toByteArray(st)
        bytes.append(scan_time[0])
        bytes.append(scan_time[1])
        bytes.append(scan_time[2])
        
        //get Common WL Value
        if(UserDefaults.standard.bool(forKey: "Interpolation_enabled")){
            if(UserDefaults.standard.integer(forKey: "Number_data_points") == 0){
                bytes.append(UInt8(5))
            }else{
                bytes.append(UInt8(UserDefaults.standard.integer(forKey: "Number_data_points")))
            }
        }else{
            bytes.append(UInt8(0))
        }
        
        //get Optical Settings Value
        let selectedOption = UserDefaults.standard.string(forKey: "Optical_gain_settings_title")
        if(selectedOption != nil){
            if(selectedOption == "Default"){
                bytes.append(UInt8(0))
            }else{
                bytes.append(UInt8(2))
            }
        }else{
            bytes.append(UInt8(0))
        }
        
        //get Apodization Window Value
        bytes.append(UInt8(UserDefaults.standard.integer(forKey: "Apodization_function")))
        
        //get zero Padding Value
        if(UserDefaults.standard.integer(forKey: "Zero_padding") == 0){
            bytes.append(UInt8(1))
        }else{
            bytes.append(UInt8(UserDefaults.standard.integer(forKey: "Zero_padding")))
        }
        
        //get Run Mode
        bytes.append(UInt8(UserDefaults.standard.integer(forKey: "Run_mode") * 5))
        
        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 isValidData () -> Bool
    {
        var error_message = ""
        if(scanTimeTF.text == "") {error_message =  "Please, fill Scan Time value."}
        else {
            let instance = NumberFormatter()
            if((instance.number(from: scanTimeTF.text!)?.doubleValue) == nil) {
                error_message =  "Please provide a valid scan time."
            }else if(Double(scanTimeTF.text!)! < 0.01){
                error_message = "Scan Time should be greater than 10 ms."
            }
        }
        
        if error_message != ""
        {
            let alertController = UIAlertController(title: "Error", message:
                error_message, preferredStyle: UIAlertControllerStyle.alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: nil))
            
            DispatchQueue.main.async {
                self.present(alertController, animated: true, completion: nil)
            }
            return false
        }
        return true
    }
    
    override func viewDidAppear(_ animated: Bool) {
        
    }
    
    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.kitInUseSpectrum){
            self.scanButton.isEnabled = false
        }else if(Constants.BlueToothConnected){
            self.scanButton.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(UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight){
            self.scanTimeConstraint.constant = 33
            if(Constants.deviceType == .iPhone6 || Constants.deviceType == .iPhone6s || Constants.deviceType == .iPhone7 || Constants.deviceType == .iPhone8){
                self.scanViewConstraint.constant = 0
            }else if(Constants.deviceType == .iPhone6Plus || Constants.deviceType == .iPhone6sPlus || Constants.deviceType == .iPhone7Plus || Constants.deviceType == .iPhone8Plus){
                self.scanViewConstraint.constant = 20
            }
        }else if(UIDevice.current.orientation == .portrait){
            self.scanTimeConstraint.constant = 66
            self.scanViewConstraint.constant = 33.5
        }
    }
    
    private var _orientations = UIInterfaceOrientationMask.portrait
    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        get { return self._orientations }
        set { self._orientations = newValue }
    }
    
    
    //MARK: - Segue methods
    override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
        //if identifier == "rawData2"{
        //    return self.doubledata.count != 0 || self.floatdata.count != 0
        //}
        return true
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "rawData2"
        {
            let nc = segue.destination as! UINavigationController
            let controller = nc.childViewControllerForStatusBarHidden as! ChartViewController
            controller.floatdata = self.floatdata
            controller.doubledata = Constants.PSDdoubledata
            controller.source = "PSD"
        }
    }
    
    //MARK: - NSBluetoothManagerDelegate
    func didConnectPeripheral(deviceName aName : String)
    {
        let delayInSeconds = 3.0
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
        //DispatchQueue.main.async {
            self.scanButton.isEnabled = true
        }
    }
    
    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.scanButton.isEnabled = false
            self.skipBoardError = 0
            self.Iteration = 1
            if(self.buttonAnimating){
                self.stopScanButtonAnimation()
                self.present(alertController, animated: true, completion: nil)
            }
        }
    }
    
    func receivedDoubleData(allData:[Double], sender:AppDelegate.MainViews)
    {
        if allData.count > 0 {
            DispatchQueue.main.async {
                //if(self.skipBoardError > 0){
                //    self.skipBoardError = 0
                //}
                if(self.Iteration == 1){
                    self.Iteration = 2
                    self.runPSD()
                }else if(self.Iteration == 2){
                    self.Iteration = 3
                    self.runPSD()
                }else{
                    if(UserDefaults.standard.integer(forKey: "Run_mode") == 1){
                        if(!Constants.PSDcaptureRequested && Constants.PSDdoubledata.count > 0 && Constants.PSDdoubledata.count > Constants.PSDstartingDataCount){
                            Constants.PSDdoubledata.removeLast()
                        }else if(Constants.PSDcaptureRequested){
                            Constants.PSDcaptureRequested = false
                        }
                    }
                    Constants.PSDdoubledata.append(allData)
                    self.Iteration = 1
                    if(self.requestedMode == 0){
                        self.stopScanButtonAnimation()
                        //self.showRawDataButton.isHidden = false
                    }else{
                        self.runPSD()
                    }
                }
            }
        }
    }
    
    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.runPSD()
            }
        }else{
            let alertController = UIAlertController(title: "Error", message:
                self.getErrorMessage(error: error), preferredStyle: UIAlertControllerStyle.alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default,handler: { (UIAlertAction)in
                Constants.reportedError = 0
            }))
            let delayInSeconds = 2.0
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) {
                //DispatchQueue.main.async {
                if(self.skipBoardError > 0){
                    self.skipBoardError = 0
                }
                self.Iteration = 1
                Constants.reportedError = error
                if(self.buttonAnimating) {self.stopScanButtonAnimation()}
                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: - ViewAnimation
    func startScanButtonAnimation()
    {
        self.floatdata = [Float]()
        //self.doubledata = [Double]()
        //self.showRawDataButton.isHidden = true
        let image1:UIImage = UIImage(named: "scan_bt1")!
        let image2:UIImage = UIImage(named: "scan_bt2")!
        let image3:UIImage = UIImage(named: "scan_bt3")!
        self.scanButton.setImage(image3, for: UIControlState.normal)
        self.scanButton.imageView!.animationImages = [image1, image2, image3]
        self.scanButton.imageView!.animationDuration = 0.75
        self.buttonAnimating = true
        self.skipBoardError = 0
        Constants.kitInUsePSD = true
        Constants.PSDstartingDataCount = Constants.PSDdoubledata.count
        Constants.reportedError = 0
        self.scanTimeTF.isEnabled = false
        self.loadPSDButton.isEnabled = false
        if(UserDefaults.standard.integer(forKey: "Run_mode") == 1){
            self.stopButton.isHidden = false
            self.scanButton.isHidden = true
            let image1:UIImage = UIImage(named: "stop_bt1")!
            let image2:UIImage = UIImage(named: "stop_bt2")!
            let image3:UIImage = UIImage(named: "stop_bt3")!
            self.stopButton.setImage(image3, for: UIControlState.normal)
            self.stopButton.imageView!.animationImages = [image1, image2, image3]
            self.stopButton.imageView!.animationDuration = 0.75
            self.stopButton.imageView!.startAnimating()
        }else{
            self.scanButton.imageView!.startAnimating()
        }
    }
    
    func stopScanButtonAnimation()
    {
        if(self.scanButton.imageView?.isAnimating)!{
            self.scanButton.imageView!.stopAnimating()
        }
        if(self.stopButton.imageView?.isAnimating)!{
            self.stopButton.imageView!.stopAnimating()
            self.scanButton.isHidden = false
        }
        self.buttonAnimating = false
        self.stopButton.isHidden = true
        self.scanTimeTF.isEnabled = true
        Constants.kitInUsePSD = false
        self.loadPSDButton.isEnabled = true
    }
    
}
