//
/* NOTICE: All information contained herein is, and remains the property of Brightinsight Inc. or its customer. 
 The intellectual and technical concepts contained herein are proprietary to Brightinsight Inc. or its customer and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law.
 Dissemination of this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from Brightinsight Inc. or its customer. Access to the source code contained herein is hereby forbidden to anyone except current Brightinsight Inc. employees, managers or contractors who have executed
 Confidentiality and Non-disclosure agreements explicitly covering such access.
 */
/**
 * System Name : BISDKCore
 * Component ID : BISDKCore
 * Description :
 * Author: Walter José Pinto
 * Copyright © : Brightinsight, Inc.
 * -----------------------
 * Revision Change
 * -----------------------
 * Author            Date             Version       Change-Description
 *========================================================================================================
 */

import Foundation

/// Dependency Injection class to inject the BI SDK modules that conforms with the `BISDKModule` protocol inside the `BISDKComponet` for an iOS app.
class BISDKCore {
    /// Variable that holds modules registered in the `BIApplication`
    private var _modules = [String: BISDKModule]()

    /// Variable has the defined `BIConfig`
    private  var _biConfig: BISDKConfig? = nil

    /**
     * Receive a list of `BISDKModule` and add to the SDK modules map
     *
     * - Parameter modules: modules list of all modules to add in the SDK
     */
    func loadModules(_ modules: [BISDKModule]) {
        modules.forEach { module in
            let moduleName = String(describing: type(of: module))
            _modules.updateValue(module, forKey: moduleName)
        }
    }

    /**
     * Set the configuration parameters available in the `BISDKCore`
     *
     * - Parameter config: instance of `BISDKConfig`
     */
    func setConfig(_ config: BISDKConfig) {
        _biConfig = config
    }

    /**
     * Run all start modules call from `BISDKModule`registered to this `BISDKCore`
     */
    func startModules() throws {
        try _modules.forEach { (_, biModule) in
            try biModule.startModule()
        }
    }

    /**
     * Get a module of a given type
     *
     * - Throws: `BISDKCoreModuleError.moduleNotFound` in case the module was not loaded before
     * - Returns: `BISDKModule` previously registered
     */
    func getModule<T: BISDKModule>() throws -> T {
        let moduleName = String(describing: T.self)
        guard let module = _modules[moduleName] else {
            throw BISDKError.moduleNotFound
        }
        return module as! T
    }
}

extension BISDKCore {
    /**
     * Get `BIConfig` value
     *
     * - Returns: `BISDKConfig` of the SDK
     * - Throws: `BISDKCoreModuleError.unconfiguredSDK`in case the config was not initialized yet
     */
    public func getBISDKConfig() throws -> BISDKConfig {
        guard let config = _biConfig else {
            throw BISDKError.unconfiguredSDK
        }
        return config
    }
}
