/*
 * 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".
 */

/* $Id$ */

#pragma once

#include "ClientAdapter/ClientAdapter.h"
#include <PortableThread.h>
#include <map>
#include "CritSection.h"

namespace NS_Logging
{
	class Logger;
}

namespace NS_DM_Client
{
	class IFIFOWrapper;
	struct Message;
	class IMgmtObject;
	class INotificationUpdater;

	namespace NS_Common
	{
		class EventEx;
	}

	class ClientAdapterProxy: public IClientAdapter
	{
		friend void SetFIFOWrappers(ClientAdapterProxy& clientAdapterProxy, NS_DM_Client::IFIFOWrapper* inFIFOWrapper,
			NS_DM_Client::IFIFOWrapper* outFIFOWrapper); // for tests only

		friend class ResponseReceiverThread;

	public:
		ClientAdapterProxy();
		virtual ~ClientAdapterProxy();

		virtual bool Open();
		virtual bool Close();
		virtual void Release();

		virtual bool GetDeviceInfo(DevInfo& deviceInfo);
		virtual bool GetDeviceDetail(DevDetail& deviceDetail);
		virtual bool GetDMAccount(DMAcc& dmAccount);
		virtual bool GetWiMAX(WiMAX& wimax);
		virtual bool GetWiMAXSupp(WiMAXSupp& wimaxSupp);

		virtual bool SetDeviceInfo(const DevInfo& deviceInfo);
		virtual bool SetDeviceDetail(const DevDetail& deviceDetail);
		virtual bool SetDMAccount(const DMAcc& dmAccount);
		virtual bool SetWiMAX(const WiMAX& wimax);
		virtual bool SetWiMAXSupp(const WiMAXSupp& wimaxSupp);
		virtual bool SetWiMAXDiagnostics(const NS_DM_Diagnostics::WiMAX_Diagnostics& wimaxDiagnostics);

		virtual bool DRMDReady();
		
		virtual bool StartDMSession(INotificationUpdater* updater);
		virtual bool CheckForFirmwareUpdate(INotificationUpdater* updater);

		virtual bool SubscribeToDMSessionNotif(INotificationUpdater* updater);
		virtual bool SubscribeToFirmwareUpdateNotif(INotificationUpdater* updater);
		virtual bool SubscribeToProvisioningUpdateNotif(INotificationUpdater* updater);
		virtual bool SubscribeToDRMDNotif(INotificationUpdater* updater);

		virtual bool UnsubscribeToDMSessionNotif(INotificationUpdater* updater);
		virtual bool UnsubscribeToFirmwareUpdateNotif(INotificationUpdater* updater);
		virtual bool UnsubscribeToProvisioningUpdateNotif(INotificationUpdater* updater);

		virtual bool GetClientProfiles(std::vector<ClientProfileInfo>& profiles);
		virtual bool SwitchClientProfile(const String& profileName);

		virtual bool HandleNetworkEntry(int homeNspID, const char* operatorName);

		virtual bool SetMgmtTree(const String& mgmtTree);
		virtual bool GetMgmtTree(const String& uri, String& mgmtTree);

		virtual bool SetEMSK(const void* buffer, size_t count);
		virtual bool GetEMSK(void*& buffer, size_t& count); // memory is allocated here, remove buffer with delete [] after using

		virtual bool SetDeviceID(const void* buffer, size_t count);

	private:
		bool receiveResponse(Message& response);
		void receiveResponse();

		bool handleGetResponse(IMgmtObject* mgmtObject, const Message& response);
		bool handleStatusResponse(const Message& response);
		bool handleGetClientProfileResponse(ClientProfileInfo& operatorProfile, const Message& response);

		bool sendRequest(const Message& request);

		bool executeSetRequest(const IMgmtObject* mgmtObject, Message& request);
		bool createSetRequest(const IMgmtObject& mgmtObject, Message& request);
		bool executeGetRequest(IMgmtObject* mgmtObject, const Message& request);
		bool executeGetRequest(String& mgmtTree, const Message& request);
		bool executeGetRequestHelper(const Message& request, Message& response);
		bool createGetRequest(const IMgmtObject& mgmtObject, Message& request);
		bool executeRequestWithNotification(const Message& request, INotificationUpdater* updater);

		typedef size_t MessageId;
		MessageId getUniqueId(MessageId& mid);
		void addMessageToQueue(MessageId msgId, Message& response, NS_Common::EventEx& notifyResponse); // synchronous queue
		void addMessageToQueue(MessageId msgId, INotificationUpdater* updater); // asynchronous queue
		bool isMessageSynchronous(MessageId msgId);
		void notifyResponse(Message& response);
		void notifyUpdater(Message& response);

		void notifyAllResponsesWithFail();

		void deleteMessageFromQueue(MessageId msgId);

		size_t getMsgSubType(const MOType& moType);
		bool detectMgmtObject(const String& mgmtTree, IMgmtObject*& mgmtObject);

	private:
		bool m_stopRunning;
		IFIFOWrapper* m_inFIFOWrapper; // for incoming messages
		IFIFOWrapper* m_outFIFOWrapper; // for outgoing messages
		NS_Logging::Logger& m_logger;
		bool m_isOpened;

		NS_Common::CritSection m_criticalSection;
		NS_Common::CritSection m_mapMutex;
		Thread* m_receiver; // thread for responses receiving

		typedef std::map<MessageId, std::pair<Message*, NS_Common::EventEx*> > SynchMessages;
		SynchMessages m_synchMessages;

		typedef std::map<MessageId, INotificationUpdater*> AsynchMessages;
		AsynchMessages m_asynchMessages;

		MessageId m_lastMsgId;
	};

}
