//
//  XPSDKConnectionMethod.swift
//  XProtect
//
//  Created by Ivelin Tsankov on 2/2/17.
//  Copyright © 2017 Milestone Systems A/S. All rights reserved.
//

import Foundation

extension XPSDKConnection {
    //MARK: login
    public func login(withSuccessHandler successHandler: SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest?  {
        log.info("Will call login")
        
        self.setConnectionState(.loggingIn)
        
        if (self.username == nil || self.password == nil) &&
            (self.tempUsername == nil || self.tempPassword == nil) &&
            (self.plainUsername == nil || self.plainPassword == nil) {
            self.setConnectionState(.disconnected)
            
            failureHandler?(NSError())
            self.makeDelegatesPerformSelector("connectiondidFailLoginWithError:", object: NSError())
            return nil
        }
        
        if self.plainUsername != nil && self.plainPassword != nil {
            self.username = self.dhe?.encrypt(self.plainUsername)
            self.password = self.dhe?.encrypt(self.plainPassword)
        } else if self.tempUsername != nil && self.tempPassword != nil {
            self.username = self.dhe?.encrypt(self.tempUsername)
            self.password = self.dhe?.encrypt(self.tempPassword)
            self.tempUsername = nil
            self.tempPassword = nil
        } else {
            self.setConnectionState(.disconnected)
            
            failureHandler?(NSError())
            self.makeDelegatesPerformSelector("connectiondidFailLoginWithError:", object: NSError())
            return nil;
        }
        
        let params: [String: String] = [XPSDKUsername: self.username!,
                                        XPSDKPassword: self.password!,
                                        XPSDKSupportsResampling: XPSDKPublicYes,
                                        XPSDKSupportsExtendedResamplingFactor: XPSDKPublicYes,
                                        XPSDKNoNextPlaylistOnDownload: XPSDKPublicYes,
                                        XPSDKClientType: XPSDKMobileClient]
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKLogin
        request.parameters = params
        
        request.successHandler = { (response) in
            self.setConnectionState(.working)
            
            self.loginProcessForResponse(response)
            
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            self.setConnectionState(.disconnected)
            self.loginError(error, forRequest: request)
            
            failureHandler?(error)
        }
        
        request.execute()
        
        return request
    }
    
    func loginProcessForResponse(_ response: XPSDKResponse) {
        if self.reachability == nil {
            self.reachability = Reachability(hostName: self.url!.host)
            NotificationCenter.default.addObserver(self, selector: Selector("reachabilityChanged:"), name: NSNotification.Name(rawValue: kNetworkReachabilityChangedNotification), object: nil)
            
            self.reachability?.startNotifier()
        }
        
        self.features = response.parameters
        log.info("Did setted features", self.features)
        
        //old connection
        self.oldConnection?.perform("setServerCapabilities:", with: self.features)
        //------
        
        self.makeDelegatesPerformSelector("connectionDidLogIn:", object: self)
    }
    
    func loginError(_ error: NSError, forRequest request: XPSDKRequest) {
        switch (error.code) {
        case SecondStepAuthentication.secondStepAuthenticationRequired.rawValue:
            // The server has accepted the username and password provided on login
            // but requires a second step authentication code to proceed
            self.makeDelegatesPerformSelector("connectionPopToRoot:", object: self)
            
            self.features = request.response!.parameters
            log.info("Did setted features", self.features)
            
            //old connection
            self.oldConnection?.perform("setServerCapabilities:", with: self.features)

            self.requestSecondStepAuthenticationPin(withSuccessHandler: nil, failureHandler: nil)
            
            break;
            
        case SecondStepAuthentication.incorrectSecondStepAuthenticationPin.rawValue:
            // Wrong second step authentication code was entered for verification, but it is still valid
            self.makeDelegatesPerformSelector("connectionCodeError:", object: self)
            break;
        case SecondStepAuthentication.insufficientUserRights.rawValue:
            self.makeDelegatesPerformSelector("connectiondidFailLoginWithError:", object: error)
            break;
        default:
            self.makeDelegatesPerformSelector("connectiondidFailLoginWithError:", object: error)
            break;
        }
    }
    
    func requestSecondStepAuthenticationPin(withSuccessHandler successHandler: SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest  {
        log.info("Will request second step authentication pin")
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKRequestSecondStepAuthenticationPin
        
        request.successHandler = { (response) in
            self.makeDelegatesPerformSelector("connectionCodeRequired:", object: self)

            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            self.setConnectionState(.disconnected)
            self.makeDelegatesPerformSelector("connectiondidFailLoginWithError:", object: error)
            failureHandler?(error)
        }
    
        request.execute()
        return request
    }
    
    func verifySecondStepAuthenticationPin(withPin pin: String, successHandler: SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest  {
        log.info("Will verify second step authentication pin")
        
        let params: [String: String] = [XPSDKSecondStepAuthenticationPin: pin]
        
        let request = XPSDKRequest(forConnection: self)
        request.parameters = params
        
        request.commandName = XPSDKVerifySecondStepAuthenticationPin
        
        //Process login?
        request.successHandler = { (response) in
            self.setConnectionState(.working)
            
            self.loginProcessForResponse(response)
            
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            self.loginError(error, forRequest: request)
            
            failureHandler?(error)
        }
        
        request.execute()
        
        return request
    }
    
    //MARK: Send live message
    func sendLiveMessage() -> XPSDKRequest  {
        log.info("Will send live message")
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKLiveMessage
        
        request.successHandler = { (response) in
            if self.state == .lostConnection {
                self.setConnectionState(.working)
                self.makeDelegatesPerformSelector("connectionDidLogIn:", object: self)
            }
            
            if let notification = response.notification {
                log.info("Did received notification", response.notification)
                
                self.makeDelegatesPerformSelector("didReceiveNotification:", object: notification)
            }
        }
        
        request.failureHandler = { (error) in
            if self.state == .lostConnection {
                if error?.code == XPConnectionError.wrongConnectionId.rawValue {
                    
                    self.connect(successHandler: { (response) in
                        self.login(withSuccessHandler: { (response) in
                            
                            }, failureHandler: { (error) in
                                
                        })
                        }, failureHandler: { (error) in
                    })
                    
                    return
                }
            }
            self.makeDelegatesPerformSelector(#selector(XPMobileSDKConnectionDelegate.connectionLostConnectivity(_:)), object: self)
//            self.loginError(error, forRequest: request)
        }
        
        request.execute()
        
        return request
    }
    
    //MARK: Get Views
    func getAllViewsAndCameras(withSuccessHandler successHandler: SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        log.info("Will get all views and cameras")
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKGetAllViewsAndCameras
        
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        return request
    }
    
    func getSubviewsOfView(withId viewId:String, successHandler: SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        log.info("Will get subviews of %@", viewId)
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKGetViews
        let params: [String: String] = [XPSDKGetViewsParamViewId: viewId]
        request.parameters = params
        
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        return request
    }

    
    //MARK: Outputs & Events
    func getOutputsAndEvents(forCameraId cameraId: String, successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        log.info("Getting O&E for: ", cameraId)
        let request = XPSDKRequest(forConnection: self)
        request.commandName = XPSDKGetOutputsAndEvents
        let params: [String: String] = [XPSDKGetOutputsParamCameraId: cameraId]
        request.parameters = params
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        return request
    }
    
    func requestActivate(forObjectId objectId: String, triggerType:String, successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        
        log.info("Activating Output/Event ", objectId)
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKRequestActivation
        
        let params: [String: String] = [XPSDKRequestActivationParamObjectId: objectId, XPSDKRequestActivationParamTriggerType: triggerType]
        request.parameters = params
        
        request.successHandler = { (response) in
        successHandler?(response)
        }
        
        request.failureHandler = { (error) in
        failureHandler?(error)
        }
        
        request.execute()
    
        return request
    }
    
    //MARK: Alarms
    func getAlarms(withCount count:Int, timestamp:String, op:String, myAlarms:Bool, excludedStates:String, excludedPriorities:String, successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        
        let myAlarmsString = myAlarms ? XPSDKGetAlarmsParamValueYes : XPSDKGetAlarmsParamValueNo
        
        log.info("Requesting \(count) alarms timestamp: \(timestamp) myAlarms: \(myAlarmsString) excluded states: \(excludedStates), excluded priorities: \(excludedPriorities)")
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKGetAlarms
        
        let params: [String: String] = [XPSDKGetAlarmsParamCount: String(count),
                                        XPSDKGetAlarmsParamTimestamp: timestamp,
                                        XPSDKGetAlarmsParamOperator: op,
                                        XPSDKGetAlarmsParamMyAlarms: myAlarmsString,
                                        XPSDKGetAlarmsParamPriority: excludedPriorities,
                                        XPSDKGetAlarmsParamState: excludedStates]
        request.parameters = params
        
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        return request
    }
    
    func getAlarm(withId alarmId:String, successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        
        log.info("Requesting alarm with id: ", alarmId)
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKGetAlarms
        
        let params: [String: String] = [XPSDKGetAlarmsParamId: alarmId]
        request.parameters = params
        
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        
        return request
    }
    
    func getAlarmDataSettings(withSuccessHandler successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        log.info("Getting alarm data settings")
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKGetAlarmDataSettings
        
        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        
        return request
    }

    func acknowledgeAlarm(withId alarmId: String, successHandler:SuccessResponse?, failureHandler: FailureBlock?) -> XPSDKRequest {
        log.info("Acknowledging alarm with id: ", alarmId)
        
        let request = XPSDKRequest(forConnection: self)
        
        request.commandName = XPSDKAcknowledgeAlarm

        let params: [String: String] = [XPSDKAcknowledgeAlarmParamId: alarmId]
        
        request.parameters = params

        request.successHandler = { (response) in
            successHandler?(response)
        }
        
        request.failureHandler = { (error) in
            failureHandler?(error)
        }
        
        request.execute()
        
        return request
    }
    

}
