/*
 * Copyright (C) 2009 - 2010 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#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>

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/* = 0*/)
	{
		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 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.size() > size)
        {
        	return false;
        }

		if (!m_EMSKSource.empty())
		{
			return getEMSKfromCustomSource(buffer, size);
		}

		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)
			emskSource = fopen(m_EMSKSource.c_str(), "rb");
			if (!emskSource)
			{
				LOG_ERROR_(m_logger, "failed to open EMSK source file: '%s'", m_EMSKSource.c_str());
				break;
			}

			struct stat emskSrcStat = { 0 };
			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 void* buffer, size_t size)
	{
		m_deviceID.clear();
		m_deviceID.resize(size);
		memcpy(&m_deviceID[0], buffer, size);
		return true;
	}
	//-------------------------------------------------------------------------------------------

	bool DummyDeviceAdapter::GetDeviceID(void* buffer, size_t& size)
	{
		if (size == 0 || m_deviceID.length() + 1 > size)
		{
			return false;
		}

		if (m_deviceID.empty())
        {
        	size = 0;
			return true;
        }

		size = m_deviceID.length() + 1;
		memcpy(buffer, &m_deviceID[0], size);
		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;
	}

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