#include "DeviceAdapter/DummyDeviceAdapter.h"

#include "ManagementObjects/DevInfo.h"
#include "ManagementObjects/DevDetail.h"
#include "ManagementObjects/DMAcc.h"
#include "ManagementObjects/WiMAX.h"
#include "ManagementObjects/WiMAXSupp.h"

#include "DeviceAdapter/FirmwareUpdate/DiskStorageFirmwareUpdater.h"

#include <sys/stat.h>

#include "common/Utils.h"

namespace NS_DM_Client
{
static const String S_loggerName("DeviceAdapter");

    DummyDeviceAdapter::DummyDeviceAdapter()
    : m_logger(NS_Logging::GetLogger(S_loggerName.c_str())),
    m_fwUpdater(0)
    {
    }
    //-------------------------------------------------------------------------------------------

DummyDeviceAdapter::~DummyDeviceAdapter()
    {
        setFirmwareUpdater(NULL);
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::Open()
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::Close()
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    void DummyDeviceAdapter::Release()
    {
        delete this;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetDeviceInfo(DevInfo& deviceInfo)
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetDeviceDetail(DevDetail& deviceDetail)
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetDMAccount(DMAcc& dmAccount)
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetWiMAX(WiMAX& wimax)
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetWiMAXSupp(WiMAXSupp& wimaxSupp)
    {
         return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetDeviceInfo(const DevInfo& deviceInfo)
    {
         return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetDeviceDetail(const DevDetail& deviceDetail)
    {
         return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetDMAccount(const DMAcc& dmAccount)
    {
        return false;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetWiMAX(const WiMAX& wimax)
    {
        return false;
    }
        //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetWiMAXSupp(const WiMAXSupp& wimaxSupp)
    {
        return false;
    }

    bool DummyDeviceAdapter::Init(const StringMap& settings, IDaemonEngineRequest* request)
    {
        StringMap& sett = const_cast<StringMap&>(settings);

        const Funambol::StringBuffer& emskSource = sett.get(EMSKSourceParam);
        if (emskSource.empty())
        {
            m_EMSKSource.clear();
        }
        else
        {
            m_EMSKSource = emskSource;
        }

        const Funambol::StringBuffer& defDevID = sett.get(DeviceIDParam);
        m_deviceID = (defDevID.empty()) ? "0:0:0:0:0:0" : defDevID.c_str();

        const Funambol::StringBuffer& netIFName = sett.get(NetworkIFParam);
        m_networkIFName = (netIFName.empty()) ? "" : netIFName.c_str();

        const Funambol::StringBuffer& defLoc = sett.get(FirmwareDefaultLocationParam);
        const char* fwDefLocation = (defLoc.empty()) ? "" : defLoc.c_str();

        const Funambol::StringBuffer& defPackage = sett.get(FirmwarePackageDefaultNameParam);
        const char* fwPackageDefName = (defPackage.empty()) ? "" : defPackage.c_str();

        const Funambol::StringBuffer& noCleanFWStorage = sett.get(FirmwareStorageNoCleanParam);
        const bool notCleanStorage = (noCleanFWStorage.empty()) ? false : atoi(noCleanFWStorage.c_str()) != 0;

        const Funambol::StringBuffer& firmwareUpdateResult = sett.get(FirmwareUpdateResultParam);
        const bool fwUpdateFailure = (firmwareUpdateResult.empty()) ? false : atoi(firmwareUpdateResult.c_str()) == 0;
        LOG_DEBUG_(m_logger, "FirmwareUpdateResultParam='%s', fwUpdateFailure=%d",
            firmwareUpdateResult.empty() ? "empty" : firmwareUpdateResult.c_str(), fwUpdateFailure);

        bool brc = initFirmwareUpdater(fwPackageDefName, fwDefLocation, notCleanStorage, fwUpdateFailure);
        LOG_DEBUG_(m_logger, "initFirmwareUpdater result= %d", brc);

        return brc;
    }

    bool DummyDeviceAdapter::initFirmwareUpdater(const char* defFWPackageName, const char* defFWPackageLocation,
        bool notCleanStorage, bool fwUpdateFailure)
    {
        setFirmwareUpdater(new(std::nothrow) DiskStorageFirmwareUpdater);
        if (m_fwUpdater)
        {
            DiskStorageFirmwareUpdater* updater = (DiskStorageFirmwareUpdater*)m_fwUpdater;
            bool brc = updater->Init(defFWPackageName, defFWPackageLocation, notCleanStorage, &m_logger);
            if (!brc)
            {
                LOG_ERROR_(m_logger, "failed to init FirmwareUpdater");
                setFirmwareUpdater(NULL);
            }

            updater->m_fwUpdateFailure = fwUpdateFailure;
            LOG_DEBUG_(m_logger, "set Firmware Update failure to=%d", fwUpdateFailure);
            return m_fwUpdater != NULL;
        }

        return false;
    }

    void DummyDeviceAdapter::setFirmwareUpdater(IFirmwareUpdater* fu)
    {
        if (m_fwUpdater)
        {
            delete m_fwUpdater;
        }

        m_fwUpdater = fu;
    }


   IFirmwareUpdater::EnumFirmwareStatus DummyDeviceAdapter::InitFirmwareStorage(const char* packageName, const char* location)
    {
        return (m_fwUpdater) ? m_fwUpdater->InitStorage(packageName, location) : IFirmwareUpdater::e_FirmwareStorageFailure;
    }


    IFirmwareUpdater::EnumFirmwareStatus DummyDeviceAdapter::ResetFirmwareStorage()
    {
        return (m_fwUpdater) ? m_fwUpdater->ResetStorage() : IFirmwareUpdater::e_FirmwareStorageFailure;
    }


    IFirmwareUpdater::EnumFirmwareStatus DummyDeviceAdapter::AppendFirmwareChunk(const char* buffer, size_t size, bool last)
    {
        return (m_fwUpdater) ? m_fwUpdater->AppendChunk(buffer, size, last) : IFirmwareUpdater::e_FirmwareStorageFailure;
    }


    IFirmwareUpdater::EnumFirmwareStatus DummyDeviceAdapter::UpdateFirmware()
    {
        return (m_fwUpdater) ? m_fwUpdater->Update() : IFirmwareUpdater::e_FirmwareStorageFailure;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetEMSK(const void* buffer, size_t size)
    {
         m_EMSKBuffer.clear();
         m_EMSKBuffer.resize(size);
         memcpy(&m_EMSKBuffer[0], buffer, size);
         return true;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetEMSK(void* buffer, size_t& size)
    {
        if (size == 0 || m_EMSKBuffer.empty() || m_EMSKBuffer.size() > size)
        {
            LOG_ERROR_(m_logger, "EMSK size=%d, buffer size=%d", m_EMSKBuffer.size(), size);
            return false;
        }

        if (!m_EMSKSource.empty())
        {
            bool brc = getEMSKfromCustomSource(buffer, size);
            LOG_DEBUG_(m_logger, "Get EMSK from '%s'", m_EMSKSource.c_str());
            return brc;
        }

        size = m_EMSKBuffer.size();
        memcpy(buffer, &m_EMSKBuffer[0], size);
        return true;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::getEMSKfromCustomSource(void* buf, size_t& size)
    {
        bool brc = false;
        FILE* emskSource = 0;
        do
        {
            if (m_EMSKSource.empty())
            {
                LOG_ERROR_(m_logger, "EMSK source is not defined");
                break;
             }

            // use file as source of EMSK (wpa_supplicant tweak by Christian Scheid)
            if ((!__fopen(m_EMSKSource.c_str(), "rb", emskSource)) || (!emskSource))
              {
                 LOG_ERROR_(m_logger, "failed to open EMSK source file: '%s'", m_EMSKSource.c_str());
                 break;
              }

            struct stat emskSrcStat;
            memset(&emskSrcStat, 0, sizeof(struct stat));
            const int statResult = stat(m_EMSKSource.c_str(), &emskSrcStat);
            if (statResult == 0)
            {
                LOG_DEBUG_(m_logger, "EMSK size (in file) = %d", emskSrcStat.st_size);
                if ((size_t)emskSrcStat.st_size > size)
                {
                    LOG_ERROR_(m_logger, "EMSK of size %d can no be fit into provided buffer of size %d. ", emskSrcStat.st_size, size);
                    break;
                 }
            }
            else
            {
                LOG_WARNING_(m_logger, "failed to get file statistics. Using defaults.");
            }

            size_t bytesRead = fread(buf, 1, size, emskSource);
            LOG_DEBUG_(m_logger, "Requested %d bytes to read from source and %d actually read.", size, bytesRead);
            size = bytesRead;

            brc = bytesRead > 0;

        }while(0);

        if (emskSource)
        {
            fclose(emskSource);
        }

         LOG_DEBUG_(m_logger, "result=%d", brc);
         return brc;
    }


//      bool DummyDeviceAdapter::GetDeviceID(char* buf, size_t& size)
//      {
//              if (size <= m_deviceID.length())
//              {
//                      return false;
//              }
// 
//              size = m_deviceID.length() + 1;
//              strncpy(buf, m_deviceID.c_str(), size);
//              return true;
//      }

    bool DummyDeviceAdapter::SetDeviceID(const String& deviceID)
    {
        m_deviceID = deviceID;
        return true;
    }
    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetDeviceID(String& deviceID)
    {
        deviceID = m_deviceID;
        return true;
    }

        //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetManufacturer(const String& manufacturer)
    {
        m_manufacturer = manufacturer;
        return true;
    }

    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetManufacturer(String& manufacturer)
    {
        manufacturer = m_manufacturer;
        return true;
    }

    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::SetModel(const String& model)
    {
        m_model = model;
        return true;
    }

    //-------------------------------------------------------------------------------------------
    bool DummyDeviceAdapter::GetModel(String& model)
    {
        model = m_model;
        return true;
    }

    //-------------------------------------------------------------------------------------------

    bool DummyDeviceAdapter::GetNetworkInterfaceName(char* buf, size_t& size)
    {
        if (size <= m_networkIFName.length())
        {
            return false;
        }

        size = m_networkIFName.length() + 1;
        __strncpy(buf, m_networkIFName.c_str(), size);
        return true;
    }

    //-------------------------------------------------------------------------------------------
}
