/*
* Copyright 2009 Funambol, Inc.
*
* 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.
*/

/* $Id$ */

#pragma once

#include "ClientAdapter/ClientAdapter.h"
#include <PortableThread.h>
#include <map>
#include "CritSection.h"
#include "MessageDefs.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 ChangeDefaultAccountPassword(const String &oldpass, const String &newpass);
		virtual bool ChangeAccountPassword(const String& serverID, const String &oldpass, const String &newpass);
		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(const String& alertMessage, IStatusCallback* statusCallback);
		virtual bool StartBootstrapRequest();
		virtual bool StartDRMD();
		virtual bool CheckForFirmwareUpdate(IStatusCallback* statusCallback);

		virtual bool SubscribeToDMSessionNotification(INotificationUpdater* updater);
		virtual bool SubscribeToFirmwareNotification(INotificationUpdater* updater);
		virtual bool SubscribeToNotification(const ProvisionInfoRequest& provInfo, INotificationUpdater* updater);
		virtual bool SubscribeToDRMDNotif(INotificationUpdater* updater);

		virtual bool SubscribeToConfirmation(IConfirmation* confirmation);
		virtual bool SendConfirmationResponse(const String& requestMessage, ResponseCode confCode);

		virtual bool UnsubscribeToDMSessionNotif();
		virtual bool UnsubscribeToFirmwareUpdateNotif();
		virtual bool UnsubscribeToProvisioningUpdateNotif();

		virtual bool GetClientProfiles(ClientProfiles& profiles);
		virtual bool SwitchClientProfile(const String& profileName);
		virtual bool GetProfileActivationStatus(bool& isActive); // check if current profile is active
		virtual bool GetProfileActivationStatus(const String& serverID, bool& isActive); // check if profile with specific ServerID is active

		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);
		virtual bool SetManufacturer(const void* buffer, size_t count);
		virtual bool SetModel(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);
		void handleNotifyProvisioningUpdate(const String& data, INotificationUpdater* updater);

		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);
		bool executeUnsubscribeRequest(const Message& request);

		typedef size_t MessageId;
		size_t& getUniqueId();
//		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);

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

	private:
		volatile 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;
		IConfirmation* m_confirmation;

		MessageId m_lastMsgId;
	};

}
