/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2016-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

/**
 * @file
 *
 * @brief
 *   Class declarations for a monotonically-increasing counter that is periodically
 *   saved to the provided storage.
 */

#pragma once

#include <lib/core/CHIPEncoding.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/support/CHIPCounter.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/DefaultStorageKeyAllocator.h>

namespace chip {

/**
 * @class PersistedCounter
 *
 * @brief
 *   A class for managing a counter as an integer value intended to persist
 *   across reboots.
 *
 * Counter values are always set to start at a multiple of a bootup value
 * "epoch".
 *
 * Example:
 *
 * - Assuming epoch is 100 via PersistedCounter::Init(_, 100) and GetValue +
 *   AdvanceValue is called, we get the following outputs:
 *
 *   - Output: 0, 1, 2, 3, 4  <reboot/reinit>
 *   - Output: 100, 101, 102, 103, 104, 105 <reboot/reinit>
 *   - Output: 200, 201, 202, ...., 299, 300, 301, 302 <reboot/reinit>
 *   - Output: 400, 401 ...
 *
 */
template <typename T>
class PersistedCounter : public MonotonicallyIncreasingCounter<T>
{
public:
    PersistedCounter() : mKey(StorageKeyName::Uninitialized()) {}
    ~PersistedCounter() override {}

    /**
     *  @brief
     *    Initialize a PersistedCounter object.
     *
     *  @param[in] aStorage the storage to use for the counter values.
     *  @param[in] aKey the key to use for storing the counter values.
     *  @param[in] aEpoch  On bootup, values we vend will start at a
     *                     multiple of this parameter.
     *
     *  @return CHIP_ERROR_INVALID_ARGUMENT if aStorageDelegate or aKey is NULL
     *          CHIP_ERROR_INVALID_INTEGER_VALUE if aEpoch is 0.
     *          CHIP_NO_ERROR otherwise
     */
    CHIP_ERROR Init(PersistentStorageDelegate * aStorage, StorageKeyName aKey, T aEpoch)
    {
        VerifyOrReturnError(aStorage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
        VerifyOrReturnError(aKey.IsInitialized(), CHIP_ERROR_INVALID_ARGUMENT);
        VerifyOrReturnError(aEpoch > 0, CHIP_ERROR_INVALID_INTEGER_VALUE);

        mStorage = aStorage;
        mKey     = aKey;
        mEpoch   = aEpoch;

        T startValue;

        // Read our previously-stored starting value.
        ReturnErrorOnFailure(ReadStartValue(startValue));

#if CHIP_CONFIG_PERSISTED_COUNTER_DEBUG_LOGGING
        if constexpr (std::is_same_v<decltype(startValue), uint64_t>)
        {
            ChipLogDetail(EventLogging, "PersistedCounter::Init() aEpoch 0x" ChipLogFormatX64 " startValue 0x" ChipLogFormatX64,
                          ChipLogValueX64(aEpoch), ChipLogValueX64(startValue));
        }
        else if (std::is_same_v<decltype(startValue), uint32_t>)
        {
            ChipLogDetail(EventLogging, "PersistedCounter::Init() aEpoch 0x%" PRIx32 " startValue 0x%" PRIx32,
                          static_cast<uint32_t>(aEpoch), static_cast<uint32_t>(startValue));
        }
#endif

        ReturnErrorOnFailure(PersistNextEpochStart(startValue + aEpoch));

        // This will set the starting value, after which we're ready.
        return MonotonicallyIncreasingCounter<T>::Init(startValue);
    }

    /**
     *  @brief
     *  Increment the counter and write to persisted storage if we've completed
     *  the current epoch.
     *
     *  @return Any error returned by a write to persisted storage.
     */
    CHIP_ERROR Advance() override
    {
        VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
        VerifyOrReturnError(mKey.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);

        ReturnErrorOnFailure(MonotonicallyIncreasingCounter<T>::Advance());

        if (MonotonicallyIncreasingCounter<T>::GetValue() >= mNextEpoch)
        {
            // Value advanced past the previously persisted "start point".
            // Ensure that a new starting point is persisted.
            ReturnErrorOnFailure(PersistNextEpochStart(mNextEpoch + mEpoch));

            // Advancing the epoch should have ensured that the current value
            // is valid
            VerifyOrReturnError(MonotonicallyIncreasingCounter<T>::GetValue() < mNextEpoch, CHIP_ERROR_INTERNAL);
        }
        return CHIP_NO_ERROR;
    }

private:
    /**
     *  @brief
     *    Write out the counter value to persistent storage.
     *
     *  @param[in] aStartValue  The counter value to write out.
     *
     *  @return Any error returned by a write to persistent storage.
     */
    CHIP_ERROR PersistNextEpochStart(T aStartValue)
    {
        mNextEpoch = aStartValue;
#if CHIP_CONFIG_PERSISTED_COUNTER_DEBUG_LOGGING
        if constexpr (std::is_same_v<decltype(aStartValue), uint64_t>)
        {
            ChipLogDetail(EventLogging, "PersistedCounter::WriteStartValue() aStartValue 0x" ChipLogFormatX64,
                          ChipLogValueX64(aStartValue));
        }
        else
        {
            ChipLogDetail(EventLogging, "PersistedCounter::WriteStartValue() aStartValue 0x%" PRIx32,
                          static_cast<uint32_t>(aStartValue));
        }
#endif

        T valueLE = Encoding::LittleEndian::HostSwap<T>(aStartValue);
        return mStorage->SyncSetKeyValue(mKey.KeyName(), &valueLE, sizeof(valueLE));
    }

    /**
     *  @brief
     *    Read our starting counter value (if we have one) in from persistent storage.
     *
     *  @param[in,out] aStartValue  The value read out.
     *
     *  @return Any error returned by a read from persistent storage.
     */
    CHIP_ERROR ReadStartValue(T & aStartValue)
    {
        T valueLE     = GetInitialCounterValue();
        uint16_t size = sizeof(valueLE);

        VerifyOrReturnError(mKey.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);

        CHIP_ERROR err = mStorage->SyncGetKeyValue(mKey.KeyName(), &valueLE, size);
        if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
        {
            // No previously-stored value, no worries, the counter is initialized to zero.
            // Suppress the error.
            err = CHIP_NO_ERROR;
        }
        else
        {
            // TODO: Figure out how to avoid a bootloop here.  Maybe we should just
            // init to 0?  Or a random value?
            ReturnErrorOnFailure(err);
        }

        if (size != sizeof(valueLE))
        {
            // TODO: Again, figure out whether this could lead to bootloops.
            return CHIP_ERROR_INCORRECT_STATE;
        }

        aStartValue = Encoding::LittleEndian::HostSwap<T>(valueLE);

#if CHIP_CONFIG_PERSISTED_COUNTER_DEBUG_LOGGING
        if constexpr (std::is_same_v<decltype(aStartValue), uint64_t>)
        {
            ChipLogDetail(EventLogging, "PersistedCounter::ReadStartValue() aStartValue 0x" ChipLogFormatX64,
                          ChipLogValueX64(aStartValue));
        }
        else
        {
            ChipLogDetail(EventLogging, "PersistedCounter::ReadStartValue() aStartValue 0x%" PRIx32,
                          static_cast<uint32_t>(aStartValue));
        }
#endif

        return CHIP_NO_ERROR;
    }

    /**
     * @brief Get the Initial Counter Value
     *
     * By default, persisted counters start off at 0.
     */
    virtual inline T GetInitialCounterValue() { return 0; }

    PersistentStorageDelegate * mStorage = nullptr; // start value is stored here
    StorageKeyName mKey;
    T mEpoch     = 0; // epoch modulus value
    T mNextEpoch = 0; // next epoch start
};

} // namespace chip
