<commit_before>//
//  ProxyManager.swift
//  SmartDeviceLink-ExampleSwift
//
//  Copyright © 2017 smartdevicelink. All rights reserved.
//

import UIKit
import SmartDeviceLink


class ProxyManager: NSObject {
    fileprivate var sdlManager: SDLManager!
    fileprivate var buttonManager: ButtonManager!
    fileprivate var firstHMILevelState: SDLHMILevelFirstState
    weak var delegate: ProxyManagerDelegate?

    // Singleton
    static let sharedManager = ProxyManager()
    private override init() {
        firstHMILevelState = .none
        super.init()
    }
}

// MARK: - SDL Configuration

extension ProxyManager {
    func start(with connectionType: SDLConnectionType) {
        delegate?.didChangeProxyState(SDLProxyState.searching)
        sdlManager = SDLManager(configuration: connectionType == .iAP ? ProxyManager.connectIAP() : ProxyManager.connectTCP(), delegate: self)
        startManager()
    }

    func resetConnection() {
        sdlManager.stop()
    }
}

// MARK: - SDL Configuration Helpers

private extension ProxyManager {
    class func connectIAP() -> SDLConfiguration {
        let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId)
        return setupManagerConfiguration(with: lifecycleConfiguration)
    }

    class func connectTCP() -> SDLConfiguration {
        let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId, ipAddress: AppUserDefaults.shared.ipAddress!, port: UInt16(AppUserDefaults.shared.port!)!)
        return setupManagerConfiguration(with: lifecycleConfiguration)
    }

    class func setupManagerConfiguration(with lifecycleConfiguration: SDLLifecycleConfiguration) -> SDLConfiguration {
        let appIcon = UIImage(named: ExampleAppLogoName)

        lifecycleConfiguration.shortAppName = ExampleAppNameShort
        lifecycleConfiguration.appIcon = appIcon != nil ? SDLArtwork(image: appIcon!, persistent: true, as: .PNG) : nil
        lifecycleConfiguration.appType = .media

        let lockScreenConfiguration = appIcon != nil ? SDLLockScreenConfiguration.enabledConfiguration(withAppIcon: appIcon!, backgroundColor: nil) : SDLLockScreenConfiguration.enabled()
        return SDLConfiguration(lifecycle: lifecycleConfiguration, lockScreen: lockScreenConfiguration, logging: logConfiguration())
    }

    class func logConfiguration() -> SDLLogConfiguration {
        let logConfig = SDLLogConfiguration.default()
        let exampleLogFileModule = SDLLogFileModule(name: "SDL Example", files: ["ProxyManager"])
        logConfig.modules = logConfig.modules.union([exampleLogFileModule])
        logConfig.targets = NSSet(array: [SDLLogTargetFile.logger()]) as! Set<AnyHashable>
        logConfig.globalLogLevel = .debug
        return logConfig
    }

    func startManager() {
        sdlManager.start(readyHandler: { [unowned self] (success, error) in
            guard success else {
                print("There was an error while starting up: \(String(describing: error))")
                self.resetConnection()
                return
            }

            // A connection has been established between the app and a SDL enabled accessory
            self.delegate?.didChangeProxyState(SDLProxyState.connected)

            // Do some setup
            self.buttonManager = ButtonManager(sdlManager: self.sdlManager, updateScreenHandler: self.updateScreenHandler)
            self.setupPermissionsCallbacks(with: self.sdlManager)

            print("SDL file manager storage: \(self.sdlManager.fileManager.bytesAvailable / 1024 / 1024) mb")
        })
    }
}

// MARK: - SDLManagerDelegate

extension ProxyManager: SDLManagerDelegate {
    func managerDidDisconnect() {
        delegate?.didChangeProxyState(SDLProxyState.stopped)
        self.firstHMILevelState = .none

        // Automatically start searching for a new connection to Core
        if ExampleAppShouldRestartSDLManagerOnDisconnect.boolValue {
            startManager()
        }
    }

    func hmiLevel(_ oldLevel: SDLHMILevel, didChangeToLevel newLevel: SDLHMILevel) {
        if newLevel != .none && firstHMILevelState == .none {
            // This is our first time in a non-NONE state
            firstHMILevelState = .nonNone

            // Send AddCommands
            prepareRemoteSystem()
        }

        if newLevel == .full && firstHMILevelState != .full {
            // This is our first time in a FULL state
            firstHMILevelState = .full

             manticoreTest()
        }

        if newLevel == .full {
            // We're always going to try to show the initial state to guard against some possible weird states
            showInitialData()
        }
    }

    func manticoreTest() {
        print("Waiting 10 seconds to send the CICS")
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10.0) {
            print("Sending the CICS")
            self.sdlManager.send(MenuManager.createChoiceSets(), progressHandler: { (request, response, error, progress) in
                print("Create Interaction Choice Set RPC sent, Response: \(response?.resultCode == .success ? "successful" : "not successful"), Percent Complete: \(progress), Error: \(String(describing: error?.localizedDescription))")
            }, completionHandler: { (success) in
                print("All Create Interaction Choice Set RPCs send successfully: \(success ? "YES" : "NO")")
            })
        }
    }

    func audioStreamingState(_ oldState: SDLAudioStreamingState?, didChangeToState newState: SDLAudioStreamingState) {
        // The audio state only needs to be monitored if the app is streaming audio
        switch newState {
        case .audible: break        // The SDL app's audio can be heard
        case .notAudible: break     // The SDL app's audio cannot be heard
        case .attenuated: break     // The SDL app's audio volume has been lowered to let the system speak over the audio. This usually happens with voice recognition commands.
        default: break
        }
    }

    func managerShouldUpdateLifecycle(toLanguage language: SDLLanguage) -> SDLLifecycleConfigurationUpdate? {
        var appName = ""

        switch language {
        case .enUs:
            appName = ExampleAppName
        case .esMx:
            appName = ExampleAppNameSpanish
        case .frCa:
            appName = ExampleAppNameFrench
        default:
            // App does not support the head-unit's language
            return nil
        }

        return SDLLifecycleConfigurationUpdate(appName: appName, shortAppName: nil, ttsName: [SDLTTSChunk(text: appName, type: .text)], voiceRecognitionCommandNames: nil)
    }
}

// MARK: - SDL UI

private extension ProxyManager {
    var updateScreenHandler: updateScreenHandler? {
        return { [weak self] () in
            self?.updateScreen()
        }
    }

    func showInitialData() {
        let nonMediaTemplate = SDLSetDisplayLayout(predefinedLayout: .nonMedia)
        if sdlManager.registerResponse?.displayCapabilities?.templatesAvailable?.contains(nonMediaTemplate.displayLayout) ?? false {
            sdlManager.send(request: nonMediaTemplate, responseHandler: nil)
        }

        updateScreen()
        sdlManager.screenManager.softButtonObjects = buttonManager.screenSoftButtons(with: sdlManager)
    }

    func updateScreen() {
        guard sdlManager.hmiLevel == .full else { return }
        let screenManager = sdlManager.screenManager
        let isTextVisible = buttonManager.textEnabled
        let areImagesVisible = buttonManager.imagesEnabled<commit_msg>Added documentation to the Swift example app<commit_after>//
//  ProxyManager.swift
//  SmartDeviceLink-ExampleSwift
//
//  Copyright © 2017 smartdevicelink. All rights reserved.
//

import UIKit
import SmartDeviceLink

class ProxyManager: NSObject {
    fileprivate var sdlManager: SDLManager!
    fileprivate var buttonManager: ButtonManager!
    fileprivate var firstHMILevelState: SDLHMILevelFirstState
    weak var delegate: ProxyManagerDelegate?

    // Singleton
    static let sharedManager = ProxyManager()
    private override init() {
        firstHMILevelState = .none
        super.init()
    }
}

// MARK: - SDL Configuration

extension ProxyManager {
    /// Configures the SDL Manager that handles data transfer beween this app and the car's head unit and starts searching for a connection to a head unit. There are two possible types of transport layers to use: TCP is used to connect wirelessly to SDL Core and is only available for debugging; iAP is used to connect to MFi (Made for iPhone) hardware and is must be used for production builds.
    ///
    /// - Parameter connectionType: The type of transport layer to use.
    func start(with connectionType: SDLConnectionType) {
        delegate?.didChangeProxyState(SDLProxyState.searching)
        sdlManager = SDLManager(configuration: connectionType == .iAP ? ProxyManager.connectIAP() : ProxyManager.connectTCP(), delegate: self)
        startManager()
    }

    /// Attempts to close the connection between the this app and the car's head unit. The `SDLManagerDelegate`'s `managerDidDisconnect()` is called when connection is actually closed.
    func resetConnection() {
        sdlManager.stop()
    }
}

// MARK: - SDL Configuration Helpers

private extension ProxyManager {
    /// Configures an iAP transport layer.
    ///
    /// - Returns: A SDLConfiguration object
    class func connectIAP() -> SDLConfiguration {
        let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId)
        return setupManagerConfiguration(with: lifecycleConfiguration)
    }


    /// Configures a TCP transport layer with the IP address and port of the remote SDL Core instance.
    ///
    /// - Returns: A SDLConfiguration object
    class func connectTCP() -> SDLConfiguration {
        let lifecycleConfiguration = SDLLifecycleConfiguration(appName: ExampleAppName, appId: ExampleAppId, ipAddress: AppUserDefaults.shared.ipAddress!, port: UInt16(AppUserDefaults.shared.port!)!)
        return setupManagerConfiguration(with: lifecycleConfiguration)
    }

    /// Helper method for setting additional configuration parameters for both TCP and iAP transport layers.
    ///
    /// - Parameter lifecycleConfiguration: The transport layer configuration
    /// - Returns: A SDLConfiguration object
    class func setupManagerConfiguration(with lifecycleConfiguration: SDLLifecycleConfiguration) -> SDLConfiguration {
        lifecycleConfiguration.shortAppName = ExampleAppNameShort
        let appIcon = UIImage(named: ExampleAppLogoName)
        lifecycleConfiguration.appIcon = appIcon != nil ? SDLArtwork(image: appIcon!, persistent: true, as: .PNG) : nil
        lifecycleConfiguration.appType = .media

        let lockScreenConfiguration = appIcon != nil ? SDLLockScreenConfiguration.enabledConfiguration(withAppIcon: appIcon!, backgroundColor: nil) : SDLLockScreenConfiguration.enabled()
        return SDLConfiguration(lifecycle: lifecycleConfiguration, lockScreen: lockScreenConfiguration, logging: logConfiguration())
    }

    /// Sets the type of SDL debug logs that are visible and where to port the logs. There are 4 levels of logs, verbose, debug, warning and error, which verbose printing all SDL logs and error printing only the error logs. Adding SDLLogTargetFile to the targest will log to a text file on the iOS device. This file can be accessed via: iTunes > Your Device Name > File Sharing > Your App Name. Make sure `UIFileSharingEnabled` has been added to the application's info.plist and is set to `true`.
    ///
    /// - Returns: A SDLLogConfiguration object
    class func logConfiguration() -> SDLLogConfiguration {
        let logConfig = SDLLogConfiguration.default()
        let exampleLogFileModule = SDLLogFileModule(name: "SDL Example", files: ["ProxyManager"])
        logConfig.modules = logConfig.modules.union([exampleLogFileModule])
        logConfig.targets = NSSet(array: [SDLLogTargetFile.logger()]) as! Set<AnyHashable> // Logs to file
        logConfig.globalLogLevel = .verbose // Filters the logs
        return logConfig
    }

    /// Searches for a connection to a SDL enabled accessory. When a connection has been established, the ready handler is called. Even though a connection has been established, it does not mean that RPCs can be immediately sent to the accessory as there is no guarentee that Core is ready to receive RPCs for this app.
    func startManager() {
        sdlManager.start(readyHandler: { [unowned self] (success, error) in
            guard success else {
                print("There was an error while starting up: \(String(describing: error))")
                self.resetConnection()
                return
            }

            // A connection has been established between the app and a SDL enabled accessory
            self.delegate?.didChangeProxyState(SDLProxyState.connected)

            // Do some setup
            self.buttonManager = ButtonManager(sdlManager: self.sdlManager, updateScreenHandler: self.updateScreenHandler)
            self.setupPermissionsCallbacks(with: self.sdlManager)

            print("SDL file manager storage: \(self.sdlManager.fileManager.bytesAvailable / 1024 / 1024) mb")
        })
    }
}

// MARK: - SDLManagerDelegate

extension ProxyManager: SDLManagerDelegate {
    /// Called when the connection beween this app and SDL Core has closed.
    func managerDidDisconnect() {
        delegate?.didChangeProxyState(SDLProxyState.stopped)
        self.firstHMILevelState = .none

        // If desired, automatically start searching for a new connection to Core
        if ExampleAppShouldRestartSDLManagerOnDisconnect.boolValue {
            startManager()
        }
    }

    /// Called when the state of the SDL app has changed. The state limits the type of RPC that can be sent. Refer to the class documentation for each RPC to determine what state(s) the RPC can be sent.
    ///
    /// - Parameters:
    ///   - oldLevel: The old SDL HMI Level
    ///   - newLevel: The new SDL HMI Level
    func hmiLevel(_ oldLevel: SDLHMILevel, didChangeToLevel newLevel: SDLHMILevel) {
        if newLevel != .none && firstHMILevelState == .none {
            // This is our first time in a non-NONE state
            firstHMILevelState = .nonNone

            // Send static menu items. Menu related RPCs can be sent at all `hmiLevel`s except `NONE`
            prepareRemoteSystem()
        }

        if newLevel == .full && firstHMILevelState != .full {
            // This is our first time in a `FULL` state.
            firstHMILevelState = .full
        }

        switch newLevel {
        case .full:                // The SDL app is in the foreground
            // Always try to show the initial state to guard against some possible weird states. Duplicates will be ignored by Core.
            showInitialData()
        case .limited: break        // The SDL app's menu is open
        case .background: break     // The SDL app is not in the foreground
        case .none: break           // The SDL app is not yet running
        default: break
        }
    }

    func manticoreTest() {
        print("Waiting 10 seconds to send the CICS")
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10.0) {
            print("Sending the CICS")
            self.sdlManager.send(MenuManager.createChoiceSets(), progressHandler: { (request, response, error, progress) in
                print("Create Interaction Choice Set RPC sent, Response: \(response?.resultCode == .success ? "successful" : "not successful"), Percent Complete: \(progress), Error: \(String(describing: error?.localizedDescription))")
            }, completionHandler: { (success) in
                print("All Create Interaction Choice Set RPCs send successfully: \(success ? "YES" : "NO")")
            })
        }
    }

    func audioStreamingState(_ oldState: SDLAudioStreamingState?, didChangeToState newState: SDLAudioStreamingState) {
        // The audio state only needs to be monitored if the app is streaming audio
        switch newState {
        case .audible: break        // The SDL app's audio can be heard
        case .notAudible: break     // The SDL app's audio cannot be heard
        case .attenuated: break     // The SDL app's audio volume has been lowered to let the system speak over the audio. This usually happens with voice recognition commands.
        default: break
        }
    }

    func managerShouldUpdateLifecycle(toLanguage language: SDLLanguage) -> SDLLifecycleConfigurationUpdate? {
        var appName = ""
        switch language {
        case .enUs:
            appName = ExampleAppName
        case .esMx:
            appName = ExampleAppNameSpanish
        case .frCa:
            appName = ExampleAppNameFrench
        default:
            return nil
        }

        return SDLLifecycleConfigurationUpdate(appName: appName, shortAppName: nil, ttsName: [SDLTTSChunk(text: appName, type: .text)], voiceRecognitionCommandNames: nil)
    }
}

// MARK: - SDL UI

private extension ProxyManager {
    var updateScreenHandler: updateScreenHandler? {
        return { [weak self] () in
            self?.updateScreen()
        }
    }

    func showInitialData() {
        let nonMediaTemplate = SDLSetDisplayLayout(predefinedLayout: .nonMedia)
        if sdlManager.registerResponse?.displayCapabilities?.templatesAvailable?.contains(nonMediaTemplate.displayLayout) ?? false {
            sdlManager.send(request: nonMediaTemplate, responseHandler: nil)
        }

        updateScreen()
        sdlManager.screenManager.softButtonObjects = buttonManager.screenSoftButtons(with: sdlManager)
    }

    func updateScreen() {
        guard sdlManager.hmiLevel == .full else { return }
        let screenManager = sdlManager.screenManager
        let isTextVisible = buttonManager.textEnabled
        let areImagesVisible = buttonManager.imagesEnabled
{'fraction_non_alphanumeric': 0.07812067150534656, 'fraction_numerical': 0.0021607845309989473, 'mean_word_length': 2.8527214514407686, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3388458', 'n_tokens_mistral': 4730, 'n_tokens_neox': 4466, 'n_words': 1473}