// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include "SMSSendSession.h"

#include <msventry.h>
#include <smutset.h>
#include <smuthdr.h>

#include "SMSSPAN.H"
#include "SMSSSEND.H"
#include "SMSRecipientSend.h"

const TInt KErrUnknownBioType = KErrNotSupported;

CSmsSendSession* CSmsSendSession::NewL(TSmsProgress& aProgress, CMsvServerEntry& aServerEntry, RFs& aFs, CSmsHeader& aHeader, CRichText& aRichText, TMsvEntry& aEntry)
	{
	CSmsSendSession* self = new (ELeave) CSmsSendSession(aProgress, aFs, aServerEntry, aHeader);
	CleanupStack::PushL(self);

	self->ConstructL(aRichText, aEntry);

	CleanupStack::Pop();

	return self;
	}

CSmsSendSession::CSmsSendSession(TSmsProgress& aProgress, RFs& aFs, CMsvServerEntry& aServerEntry, CSmsHeader& aHeader)
	: CSmssActive(aFs, aServerEntry, KSmsSessionPriority), iProgress(aProgress), iSmsHeader(aHeader)
	{
	CActiveScheduler::Add(this);
	}

CSmsSendSession::~CSmsSendSession()
	{
	if (iSendTypes)
		iSendTypes->ResetAndDestroy();

	delete iSendTypes;
	delete iSmsSend;
	}

void CSmsSendSession::ConstructL(CRichText& aRichText, TMsvEntry& aEntry)
	{
	iSendTypes = new (ELeave) CArrayPtrFlat<CSmsSendType>(1);
	iSmsSend = CSmsSend::NewL(iProgress, iServerEntry, iFs, iSmsHeader, aRichText, aEntry);
	}

void CSmsSendSession::DivideMessagesL(CMsvEntrySelection& aSelection)
	{
	iProgress.iMsgCount = 0;
	TInt selCount = aSelection.Count();

	if (!selCount)
		User::Leave(KErrNotFound);

	CreateRecipientsL();
	const TInt typeCount = iSendTypes->Count();
	TInt divideError = KErrNone; //Used later as the error code to leave with if aSelection.Count() == 0

	//Order important
	while (selCount--)
		{
		TMsvId id = aSelection[selCount];
		TInt err = iServerEntry.SetEntry(id);
    	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DivideMessagesL() - switch to entry: %d, err: %d"), id, err ));

		if (!err)
			{
			TMsvEntry entry = iServerEntry.Entry();

			if(entry.InPreparation())
				{
		    	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DivideMessagesL() - entry is in preparation - deleting it from selection array...")));
				aSelection.Delete(selCount);
				}
			else
				{   
				//Restore the CSmsHeader
				CMsvStore* store = NULL;
				TInt error = KErrNone;
				TRAP(error, store = iServerEntry.ReadStoreL());
				if(error == KErrAccessDenied )
					{
		    		SMSSLOG(FLogFormat(_L8("CSmsSendSession::DivideMessagesL() - Error = -21 - deleting it from selection array...")));
					entry.SetSendingState(KMsvSendStateWaiting);
					iServerEntry.ChangeEntry(entry);
					aSelection.Delete(selCount);
					}
				else
					{
					User::LeaveIfError(error);
					CleanupStack::PushL(store);
					iSmsHeader.RestoreL(*store);
					CleanupStack::PopAndDestroy(); //store

					TBool msgAdded = EFalse;

					for(TInt curType = 0; curType < typeCount && !msgAdded; curType++)
						{
						CSmsSendType* smsType = iSendTypes->At(curType);
		
						if (smsType->iRecipientSend->AcceptMessage(entry, iSmsHeader))
							{
							smsType->iSelection->InsertL(0, id);
							iProgress.iMsgCount++;
							msgAdded = ETrue;
							}
						} //end for curType

					if (!msgAdded)
						{
						SMSSLOG(FLogFormat(_L8("\tCannot send message %d - Invalid bioType (%d) and bioIdType (%d) combination"), id, entry.iBioType, iSmsHeader.BioMsgIdType()));

						//Message is not going to be sent, so set failed
						entry.SetFailed(ETrue);
						entry.SetSendingState(KMsvSendStateFailed);
						entry.iError = KErrUnknownBioType;
						divideError = KErrUnknownBioType;
						iServerEntry.ChangeEntry(entry); //ignore error?

						aSelection.Delete(selCount);
						}	
					}
				}
			} 
		else //SetEntry() failed
			{
			SMSSLOG(FLogFormat(_L8("\tCannot send message %d - iServerEntry.SetEntry(%d) returned error %d"), id, id, err));

			if (err != KErrNotFound && err != KErrLocked)
				User::Leave(err);

			if (!divideError && divideError != KErrUnknownBioType)
				divideError = err;

			aSelection.Delete(selCount);
			}
		} //end for curMsg

	if (!iProgress.iMsgCount)
		{
		SMSSLOG(FLogFormat(_L8("\tNO messages to send - CSmsSendSession::DivideMessagesL() error %d"), divideError));
		User::Leave(divideError);
		}
    SMSSLOG(FLogFormat(_L8("CSmsSendSession::DivideMessagesL() - END") ));
	}

void CSmsSendSession::CreateRecipientsL()
	{
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::CreateRecipientsL() - iServerEntry id: %d"), iServerEntry.Entry().Id() ));
	//Create WAP and Text Recipients.
	//Note: The order of adding rcptWap and rcptText to iSendTypes is important
	//because rcptText->AcceptMessage() always returns ETrue, therefore rcptWap
	//must be inserted before rcptText.

	//Create a Wap Recipient
	CWapRecipientSend* rcptWap = CWapRecipientSend::NewL(iProgress, iFs, iServerEntry);
	CleanupStack::PushL(rcptWap);
	CSmsSendType* smsType = CSmsSendType::NewL(rcptWap);
	CleanupStack::PushL(smsType);
	iSendTypes->AppendL(smsType);
	CleanupStack::Pop(2); //rcptWap, smsType

	//Create a Text Recipient
	CTextRecipientSend* rcptText = CTextRecipientSend::NewL(iProgress, iFs, iServerEntry);
	CleanupStack::PushL(rcptText);
	smsType = CSmsSendType::NewL(rcptText);
	CleanupStack::PushL(smsType);
	iSendTypes->AppendL(smsType);
	CleanupStack::Pop(2); //rcptText, smsType
	}

TMsvId CSmsSendSession::IncSms()
	{
	CSmsSendType* sendType = NULL;
	TInt typeCount = iSendTypes->Count();

	iId = 0;

	if (typeCount)
		{
		while (iCurrentSendType < typeCount && !iId)
			{
			sendType = iSendTypes->At(iCurrentSendType);
			CMsvEntrySelection& selection = *(sendType->iSelection);
			sendType->iCurrentMessage++;

			if (sendType->iCurrentMessage < selection.Count())
				{
				iId = selection[sendType->iCurrentMessage];
				}
			else
				{
				iCurrentSendType++;
				}
			}
		}

	return iId;
	}

void CSmsSendSession::SendSms(TRequestStatus& aStatus)
	{
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::SendSms() - START - iId: %d"), iId ));
	Queue(aStatus);

	if (iId)
		{
		iState = ESessionSending;
		CSmsSendType* sendType = iSendTypes->At(iCurrentSendType);
		iSmsSend->Start(iStatus, iId, sendType->iRecipientSend);
		}
	else
		{
		iState = ESessionNoMoreMessages;
		RequestComplete(&iStatus, KErrNotFound, EFalse);
		}

	SetActive();
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::SendSms() - END - iId: %d, iState: %d"), iId, iState ));
	}

void CSmsSendSession::DoSmssCancel()
	{
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DoSmssCancel() - iId: %d, iState: %d"), iId, iState ));
	switch (iState)
		{
		case ESessionSending:
			iSmsSend->Cancel();
			break;
		default:
			break;
		}
	}

void CSmsSendSession::DoRunL()
	{
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DoSmssCancel() - START - iId: %d, iState: %d"), iId, iState ));
	switch (iState)
		{
		case ESessionSending:
			break;
		case ESessionNoMoreMessages:
		case ESessionNoSendTypes:
			iProgress.iError = KErrNotFound;
			break;
		default:
			Panic(KSmssPanicUnexpectedState);
		}
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DoSmssCancel() - END - iId: %d, iState: %d"), iId, iState ));
	}

void CSmsSendSession::DoComplete(TInt& aStatus)
	{
	SMSSLOG(FLogFormat(_L8("CSmsSendSession::DoSmssCancel() - aStatus: %d, iState: %d, iProgress.iError: %d"), aStatus, iState, iProgress.iError ));
	if (aStatus != KErrNone && iProgress.iError == KErrNone)
		{
		iProgress.iError = aStatus;
		}

	aStatus = KErrNone;
	}

CSmsSendSession::CSmsSendType* CSmsSendSession::CSmsSendType::NewL(CSmsRecipientSend* aRecipient)
	{
	CSmsSendType* self = new (ELeave) CSmsSendType(aRecipient);
	CleanupStack::PushL(self);

	self->ConstructL();

	CleanupStack::Pop();

	return self;
	}

CSmsSendSession::CSmsSendType::CSmsSendType(CSmsRecipientSend* aRecipient)
: iRecipientSend(aRecipient), iCurrentMessage(-1)
	{
	}

CSmsSendSession::CSmsSendType::~CSmsSendType()
	{
	delete iRecipientSend;
	delete iSelection;
	}

void CSmsSendSession::CSmsSendType::ConstructL()
	{
	iSelection = new (ELeave) CMsvEntrySelection();
	}
