/**
 * @file    drive.cpp
 * @brief   represent physical drive
 * @author  hendrik schutter
 * @date    01.05.2020
 */

#include "../include/reHDD.h"

string Drive::getPath(void)
{
    return sPath;
}

string Drive::getModelFamily(void)
{
    return sSmartData.sModelFamily;
}

string Drive::getModelName(void)
{
    return sSmartData.sModelName;
}

string Drive::getSerial(void)
{
    return sSmartData.sSerial;
}

uint64_t Drive::getCapacity(void)
{
    return sSmartData.u64Capacity;
}

uint32_t Drive::getErrorCount(void)
{
    return sSmartData.u32ErrorCount;
}
uint32_t Drive::getPowerOnHours(void)
{
    return sSmartData.u32PowerOnHours;
}

uint32_t Drive::getPowerCycles(void)
{
    return sSmartData.u32PowerCycles;
}

uint32_t Drive::getTemperature(void)
{
    return sSmartData.u32Temperature;
}

string Drive::sCapacityToText()
{
    char acBuffer[16];
    double dSize = (double) getCapacity();
    uint16_t u16UnitIndex = 0;
    const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
    while (dSize >= 1000)   //using the marketing capacity
        {
            dSize /= 1000;
            u16UnitIndex++;
        }

    sprintf(acBuffer, "%.*f %s", u16UnitIndex-3, dSize, units[u16UnitIndex]);
    return acBuffer;
}

string Drive::sErrorCountToText()
{
    return to_string(getErrorCount());
}

string Drive::sPowerOnHoursToText()
{
    double dDays = 0U;
    double dYears = 0U;
    uint32_t u32Hours = getPowerOnHours();
    stringstream streamDays;
    stringstream streamYears;

    dDays = (double) ((double)u32Hours/(double)24U);
    dYears = (double) ((double)u32Hours/(double)8760U);

    streamDays << fixed << setprecision(0) << dDays;
    streamYears << fixed << setprecision(1) << dYears;

    string sRet = to_string(getPowerOnHours()) + " hours or " + streamDays.str() + " days or " + streamYears.str() + " years";

    return sRet;
}

string Drive::sPowerCyclesToText()
{
    return to_string(getPowerCycles());
}

string Drive::sTemperatureToText()
{
    return to_string(getTemperature())+" C";;
}

void Drive::setTaskPercentage(double d32TaskPercentage)
{
    if(d32TaskPercentage <= 100)
        {
            this->d32TaskPercentage = d32TaskPercentage;
            this->setTimestamp(); //set timestamp for this progress for detecting a frozen drive
        }
}
double Drive::getTaskPercentage(void)
{
    return this->d32TaskPercentage;
}


/**
 * \brief   set S.M.A.R.T. values in model
 * \param	string modelFamily
 * \param   string modelName
 * \param   string serial
 * \param   uint64_t capacity
 * \param   uint32_t errorCount
 * \param   uint32_t powerOnHours
 * \param   uint32_t powerCycle
 * \param   uint32_t temperature
 * \return  void
 */
void Drive::setDriveSMARTData( string modelFamily,
                               string modelName,
                               string serial,
                               uint64_t capacity,
                               uint32_t errorCount,
                               uint32_t powerOnHours,
                               uint32_t powerCycle,
                               uint32_t temperature)
{
    this->sSmartData.sModelFamily = modelFamily;
    this->sSmartData.sModelName = modelName;
    this->sSmartData.sSerial = serial;
    this->sSmartData.u64Capacity = capacity;
    this->sSmartData.u32ErrorCount = errorCount;
    this->sSmartData.u32PowerOnHours = powerOnHours;
    this->sSmartData.u32PowerCycles = powerCycle;
    this->sSmartData.u32Temperature = temperature;
}

void Drive::setTimestamp()
{
    time(&this->u32Timestamp);
}

void Drive::setActionStartTimestamp()
{
    time(&this->u32TimestampTaskStart);
}

time_t Drive::getActionStartTimestamp()
{
    return this->u32TimestampTaskStart;
}

void Drive::calculateTaskDuration()
{
    time_t u32localtime;
    time(&u32localtime);

    this->u32TaskDuration = u32localtime - this->u32TimestampTaskStart;
}

time_t Drive::getTaskDuration()
{
    return this->u32TaskDuration;
}

void Drive::checkFrozenDrive(void)
{
    time_t u32localtime;
    time(&u32localtime);

    if((u32localtime - this->u32Timestamp) >= (FROZEN_TIMEOUT*60) && (this->u32Timestamp > 0) && (this->getTaskPercentage() < 100.0))
        {
            Logger::logThis()->warning("Drive Frozen: " + this->getModelName() + " " + this->getSerial());
            this->bWasDeleted = false;
            this->bWasShredded = false;
            this->state = Drive::FROZEN;
        }
}