/* 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 : BISDKContext
 * Description :
 * Author: Walter José Pinto
 * Copyright © : Brightinsight, Inc.
 * -----------------------
 * Revision Change
 * -----------------------
 * Author            Date             Version       Change-Description
 *
 *========================================================================================================
 */

import Foundation

/**
 * `BISDKContext` object that holds the SDK instance. This object it's responsible
 * for starting the application and hold an static instance of the SDK.
 *
 * It was implemented in a way that guarantees that only one instance of the SDK will
 * be running.
 */
public class BISDKContext {
    /// `BISDKContext` singleton object
    public static var shared: BISDKContext = {
        let instance = BISDKContext()
        return instance
    }()
    
    /// Variable the holds the `BISDKCore` instance created when starting the `BISDKInitializationHelper`
    private var _biSDKCore: BISDKCore? = nil
    
    private init() { }
    
    /**
     * Start the BI context and therefore the SDK using DSL
     *
     * - Parameter biAppDeclaration: `BISDKInitializationHelper` that will be registered in the context
     * - Throws: `BiApplicationAlreadyStartedException`  when trying to register another application to the same context
     */
    public func initializeBISDK(apply biAppDeclaration: (BISDKInitializationHelper) -> Void) throws {
        let biApplication = BISDKInitializationHelper()
        biAppDeclaration(biApplication)
        try register(biApplication)
    }
}

extension BISDKContext {
    /**
     * Get a reference for the current instantiated `BISDKCore` running in the context
     *
     * - Returns: `BISDKCore` of the current context
     * - Throws: `BISDKCoreModuleError.notStartedSDK` error when trying to get the SDK without starting the `BISDKInitializationHelper`
     */
    func get() throws -> BISDKCore {
        guard let biSDKCore = _biSDKCore else {
            throw BISDKError.notStartedSDK
        }
        return biSDKCore
    }
}

extension BISDKContext: NSCopying {

    public func copy(with zone: NSZone? = nil) -> Any {
        return self
    }
}

private extension BISDKContext {
    /**
     * Try to register the `BISDKInitializationHelper`to the current context
     *
     * - Parameter biApplication: The `BISDKInitializationHelper` to register in the current context
     * - Throws: `BISDKCoreModuleError.alreadyStartedSDK` when trying to register another application to the same context
     */
    func register(_ biApplication: BISDKInitializationHelper) throws {
        if (self._biSDKCore != nil) {
            throw BISDKError.alreadyStartedSDK
        }
        let bisdkCore = biApplication.bisdk
        _biSDKCore = bisdkCore
        try bisdkCore.startModules()
    }
}
