All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.dk.cachet.carp.common.application.sampling.BatteryAwareSampling.kt Maven / Gradle / Ivy

package dk.cachet.carp.common.application.sampling

import dk.cachet.carp.common.application.data.DataTypeMetaData
import dk.cachet.carp.common.application.devices.DeviceDescriptor
import kotlinx.serialization.Serializable
import kotlin.reflect.KClass


/**
 * A sampling scheme which changes based on how much battery the device has left.
 */
abstract class BatteryAwareSamplingScheme<
    TConfig : SamplingConfiguration,
    TBuilder : SamplingConfigurationBuilder
>(
    dataType: DataTypeMetaData,
    /**
     * The builder to construct [SamplingConfiguration]s when overriding configurations for different battery levels.
     */
    private val builder: () -> TBuilder,
    /**
     * The default sampling configuration to use when there is plenty of battery left.
     */
    private val normal: TConfig,
    /**
     * The default sampling configuration to use when the battery is low.
     */
    private val low: TConfig? = null,
    /**
     * The default sampling configuration to use when the battery is critically low.
     * By default, sampling should be disabled at this point.
     */
    private val critical: TConfig? = null
) : DataTypeSamplingScheme>( dataType )
{
    private val configurationKlass: KClass = normal::class


    override fun createSamplingConfigurationBuilder(): BatteryAwareSamplingConfigurationBuilder =
        BatteryAwareSamplingConfigurationBuilder( builder, normal, low, critical )

    override fun isValid( configuration: SamplingConfiguration ): Boolean
    {
        if ( configuration !is BatteryAwareSamplingConfiguration<*> ) return false

        // Verify whether battery-level-specific configurations are the expected type.
        val correctTypes =
            configurationKlass.isInstance( configuration.normal ) && // Normal configuration cannot be null.
            ( configuration.low == null || configurationKlass.isInstance( configuration.low ) ) &&
            ( configuration.critical == null || configurationKlass.isInstance( configuration.critical ) )
        if ( !correctTypes ) return false

        // Verify whether constraints for the battery-level-specific configurations are met.
        @Suppress( "UNCHECKED_CAST" )
        return isValidBatteryLevelConfiguration( configuration.normal as TConfig ) &&
            ( configuration.low == null || isValidBatteryLevelConfiguration( configuration.low as TConfig ) ) &&
            ( configuration.critical == null || isValidBatteryLevelConfiguration( configuration.critical as TConfig ) )
    }

    /**
     * Determines whether the [configuration] assigned to a specific battery level in a [BatteryAwareSamplingConfiguration]
     * is valid for the constraints defined in this sampling scheme.
     */
    abstract fun isValidBatteryLevelConfiguration( configuration: TConfig ): Boolean
}


/**
 * A sampling configuration which changes based on how much battery the device has left.
 */
@Serializable
data class BatteryAwareSamplingConfiguration(
    /**
     * The sampling configuration to use when there is plenty of battery left.
     */
    val normal: TConfig,
    /**
     * The sampling configuration to use when the battery is low.
     */
    val low: TConfig? = null,
    /**
     * The sampling configuration to use when the battery is critically low.
     */
    val critical: TConfig? = null
) : SamplingConfiguration


/**
 * A helper class to configure and construct immutable [BatteryAwareSamplingConfiguration] classes
 * as part of setting up a [DeviceDescriptor].
 */
class BatteryAwareSamplingConfigurationBuilder<
    TConfig : SamplingConfiguration,
    TBuilder : SamplingConfigurationBuilder
>(
    private val createBuilder: () -> TBuilder,
    private var normal: TConfig,
    private var low: TConfig?,
    private var critical: TConfig?
) : SamplingConfigurationBuilder>
{
    /**
     * The sampling configuration to use when there is plenty of battery left.
     */
    fun batteryNormal( builder: TBuilder.() -> Unit ) =
        createConfiguration( builder ).let { normal = it }

    /**
     * The sampling configuration to use when the battery is low.
     */
    fun batteryLow( builder: TBuilder.() -> Unit ) =
        createConfiguration( builder ).let { low = it }

    /**
     * The sampling configuration to use when the battery is critically low.
     */
    fun batteryCritical( builder: TBuilder.() -> Unit ) =
        createConfiguration( builder ).let { critical = it }

    /**
     * Apply the same sampling configuration for all battery levels: normal, low, and critical.
     */
    fun allBatteryLevels( builder: TBuilder.() -> Unit ) =
        createConfiguration( builder ).let {
            normal = it
            low = it
            critical = it
        }

    private fun createConfiguration( builder: TBuilder.() -> Unit ) =
        createBuilder().apply( builder ).build()

    override fun build(): BatteryAwareSamplingConfiguration =
        BatteryAwareSamplingConfiguration( normal, low, critical )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy