/* 
    Copyright (C) 2004  Mika Raento - Renaud Petit
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    
    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 General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    
    email: mraento@cs.helsinki.fi - petit@cs.helsinki.fi 
*/


#include "mms.h"

#include <mtclreg.h>                        // for CClientMtmRegistry 
#include <msvuids.h>
#include <mmsclient.h>
#include <mtmdef.h>
#include <mmsconst.h>
#include <MSVIDS.H>

#include <checkedactive.h>
#include <app_context.h>
#include <symbian_auto_ptr.h>

#include "Context_logapp.h"

class dummyhandler: public MMsvSessionObserver {
public:
	virtual void HandleSessionEventL(TMsvSessionEvent, TAny*, TAny*, TAny*) { }
};

class CMMSImpl : public MMsvSessionObserver, public CMMS
{
public:
	~CMMSImpl();
private:
	CMMSImpl();
	void ConstructL();
	void RunL();
	void DoCancel();
	TInt SendMessage(const TDesC& recipient, const TDesC& body, const TDesC& attachment, TDes& Errmsg, bool keep_sent=true);
	virtual void HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3);	
	void SendMessageL(const TDesC& recipient, const TDesC& body, const TDesC& attachment, bool keep_sent=true);
	
	TBool DeleteSentEntry(TMsvId aEntryId);
	
	CMsvSession* iSession;
	CClientMtmRegistry* iMtmReg;
	CBaseMtm*	iMtm;
	
	CMsvSession* iReceiveSession;
	CClientMtmRegistry* iReceiveMtmReg;
	CBaseMtm*	iReceiveMtm;
	
	TBuf<50> state;
	CMsvOperation* op;
	dummyhandler dummy;

	friend class CMMS;
};


CMMS::CMMS() : CActive(EPriorityIdle)
{
}

CMMS* CMMS::NewL()
{
	auto_ptr<CMMSImpl> ret(new (ELeave) CMMSImpl);
	ret->ConstructL();
	return ret.release();
}

CMMSImpl::CMMSImpl()
{
}

CMMSImpl::~CMMSImpl()
{
	CALLSTACKITEM(_L("CMMSImpl::~sms"));
	
	Cancel();
	
	delete op;
	delete iMtm;
	delete iMtmReg;
	delete iSession;

	delete iReceiveMtm;
	delete iReceiveMtmReg;
	delete iReceiveSession;
}

void CMMSImpl::ConstructL()
{
	CALLSTACKITEM(_L("CMMSImpl::ConstructL"));
	
	iSession = CMsvSession::OpenSyncL(dummy); // new session is opened synchronously
	iMtmReg = CClientMtmRegistry::NewL(*iSession);
	iMtm = iMtmReg->NewMtmL(KUidMsgTypeMultimedia);
	
	iReceiveSession = CMsvSession::OpenSyncL(*this); // new session is opened synchronously
	iReceiveMtmReg = CClientMtmRegistry::NewL(*iReceiveSession);
	iReceiveMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeMultimedia);
	
	CActiveScheduler::Add(this); // add to scheduler
}

TInt CMMSImpl::SendMessage(const TDesC& recipient, const TDesC& body, const TDesC& attachment, TDes& ErrMsg, bool keep_sent)
{
	CALLSTACKITEM(_L("CMMSImpl::SendMessage"));
	
	TRAPD(err, SendMessageL(recipient, body, attachment, keep_sent));
	if (err!=KErrNone) ErrMsg=state;
	else ErrMsg.Zero();
	return err;
}

void CMMSImpl::SendMessageL(const TDesC& recipient, const TDesC& body, const TDesC& attachment, bool keep_sent)
{
	CALLSTACKITEM(_L("CMMSImpl::send_messageL"));
	
	if (iStatus==KRequestPending) {
		User::Leave(KErrServerBusy);
	}
	
	state=_L("send_messageL");
	
	// To handle the sms specifics we start using MmsMtm
	CMmsClientMtm* iMmsMtm = STATIC_CAST(CMmsClientMtm*, iMtm);
	
	state=_L("SwitchCurrentEntryL");
	// Set context to the parent folder (Drafts)
	iMmsMtm->SwitchCurrentEntryL(KMsvDraftEntryId);
	// Create new message in the parent folder and set it
	// as the current context. Note that this method marks
	// the message as invisible and in preparation. This will
	// prevent it from being tampered with during
	// preparation.
	state=_L("CreateMessageL");
	iMmsMtm->CreateMessageL(iMmsMtm->DefaultSettingsL());	
	
	state=_L("AddAddresseeL");
	iMmsMtm->AddAddresseeL(recipient);
	
	if (body.Length()>0) {
		state=_L("CreateTextAttachmentL");
		TMsvId textid;
		iMmsMtm->CreateTextAttachmentL(textid, body);
	}

	if (attachment.Length()>0) {
		state=_L("CreateTextAttachmentL");
		TMsvId attid;
		iMmsMtm->CreateAttachment2L(attid, attachment);
	}
	
	state=_L("set flags");
	// Set the message’s status flags appropriately
	TMsvEntry ent = iMmsMtm->Entry().Entry();
	ent.SetInPreparation(EFalse);
	ent.SetVisible(ETrue);
	// if message is to be deleted after sending, mark with our UID
	if (!keep_sent) {
		ent.iMtmData3 = KUidcontext_log.iUid;
	}
	state=_L("save");
	// Save changes (If you do not call this method, all changes
	// made will be lost when the context is changed.)
	iMmsMtm->Entry().ChangeL(ent); // Commit changes
	iMmsMtm->SaveMessageL();
	
	state=_L("send");
	iStatus=KRequestPending;
	op = iMmsMtm->SendL(iStatus);
	
	SetActive();
	
}

void CMMSImpl::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
{
	CALLSTACKITEM(_L("CMMSImpl::HandleSessionEventL"));
	
	switch(aEvent) {
		
	case EMsvEntriesMoved:      // this event is given when message entries are moved
		{
			// An entry has been moved to another parent
			// We are interested messages that have been moved to Sent folder
			if (!aArg1 || !aArg2 || !aArg3 ) return;
			
			TMsvId* toEntryId;
			TMsvId* fromEntryId;
			toEntryId = static_cast<TMsvId*>(aArg2); 
			fromEntryId = static_cast<TMsvId*>(aArg3);
			
			CMsvEntrySelection* entries = static_cast<CMsvEntrySelection*>(aArg1);
			
			if ( *toEntryId == KMsvSentEntryId )   // the entry has been moved into Sent folder
			{
				// We take the moved entries into a selection
				
				//Process each created entry, one at a time.
				for(TInt i = 0; i < entries->Count(); i++)
				{
					DeleteSentEntry(entries->At(i)); // this checks the entry and deletes if it is created by GDSMS app
				}
				
			}
		}
		break;
	default:
		break;
	}
	
}

TBool CMMSImpl::DeleteSentEntry(TMsvId entry)
{
	CALLSTACKITEM(_L("CMMSImpl::DeleteSentEntry"));
	
	TInt err;
	// Load this entry to our mtm
	TRAP(err, iReceiveMtm->SwitchCurrentEntryL(entry));
	// probably wasn't compatible, ignore
	if (err!=KErrNone) return EFalse;
	TRAP(err, iReceiveMtm->LoadMessageL());
	// probably wasn't compatible, ignore
	if (err!=KErrNone) return EFalse;
	
	TMsvEntry msvEntry( (iReceiveMtm->Entry()).Entry() );
	
        if (msvEntry.iMtmData3 == KUidcontext_log.iUid)    // this entry has been created by our app
	{
		// Taking a handle to the Sent folder...
		TMsvSelectionOrdering sort;
		sort.SetShowInvisibleEntries(ETrue);    // we want to handle also the invisible entries
		// Take a handle to the parent entry
		CMsvEntry* parentEntry = CMsvEntry::NewL(iReceiveMtm->Session(), msvEntry.Parent(), sort);
		CleanupStack::PushL(parentEntry);
		
		// here parentEntry is the Sent folder (must be so that we can call DeleteL) 
		parentEntry->DeleteL(msvEntry.Id());
		
		CleanupStack::PopAndDestroy(parentEntry);
		
		return ETrue; // entry was deleted
	}
	
	return EFalse; // no entries deleted
}

void CMMSImpl::RunL()
{
}

void CMMSImpl::DoCancel()
{
}
