/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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.
 */

#define LOG_TAG "easelstateresidency"

#include <android-base/logging.h>
#include <fstream>
#include "EaselStateResidencyDataProvider.h"

namespace android {
namespace device {
namespace google {
namespace wahoo {
namespace powerstats {

const uint32_t EASEL_SYNTHETIC_SLEEP_ID = 0;

EaselStateResidencyDataProvider::EaselStateResidencyDataProvider(uint32_t id) :
    mPowerEntityId(id), mTotalOnSnapshotCount(0), mTotalNotOnSnapshotCount(0) {}

bool EaselStateResidencyDataProvider::getResults(
    std::unordered_map<uint32_t, PowerEntityStateResidencyResult> &results) {
    const std::string path = "/sys/devices/virtual/misc/mnh_sm/state";

    enum easel_state {
        EASEL_OFF = 0,
        EASEL_ON,
        EASEL_SUSPENDED,
        NUM_EASEL_STATES
    };

    // Since we are storing stats locally but can have multiple parallel
    // callers, locking is required to ensure stats are not corrupted.
    std::lock_guard<std::mutex> lock(mLock);

    std::ifstream inFile(path, std::ifstream::in);
    if (!inFile.is_open()) {
        PLOG(ERROR) << __func__ << ":Failed to open file " << path;
        return false;
    }

    unsigned long currentState;
    if(!(inFile >> currentState) || currentState >= NUM_EASEL_STATES) {
        PLOG(ERROR) << __func__ << ":Failed to parse " << path;
        return false;
    }

    // Update statistics for synthetic sleep state.  We combine OFF and
    // SUSPENDED to act as a composite "not on" state so the numbers will behave
    // like a real sleep state.
    if ((currentState == EASEL_OFF) || (currentState == EASEL_SUSPENDED)) {
        mTotalNotOnSnapshotCount++;
    } else {
        mTotalOnSnapshotCount++;
    }

    // Update statistics for synthetic sleep state, where
    // totalStateEntryCount = cumulative count of Easel state0 and state2 
    // (as seen by power.stats HAL)
    // totalTimeInStateMs = cumulative count of Easel state1 (as seen by
    //   power.stats HAL)
    PowerEntityStateResidencyResult result = {
        .powerEntityId = mPowerEntityId,
        .stateResidencyData = {{.powerEntityStateId = EASEL_SYNTHETIC_SLEEP_ID,
                                .totalStateEntryCount = mTotalOnSnapshotCount,
                                .totalTimeInStateMs = mTotalNotOnSnapshotCount,
                                .lastEntryTimestampMs = 0}}
    };

    results.emplace(std::make_pair(mPowerEntityId, result));
    return true;
}


std::vector<PowerEntityStateSpace> EaselStateResidencyDataProvider::getStateSpaces() {
    return {
        {.powerEntityId = mPowerEntityId,
            .states = {
                {
                 .powerEntityStateId = EASEL_SYNTHETIC_SLEEP_ID,
                 .powerEntityStateName = "SyntheticSleep"
                }
            }
        }
    };
}

}  // namespace powerstats
}  // namespace wahoo
}  // namespace google
}  // namespace device
}  // namespace android