// Copyright (c) 2008-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:
// cmdnsconsistencymgr.cpp
// 
//
/**
@file
@internalTechnology
*/

//User include
#include "cmdnscacheconsistencymgr.h"
#include "cmdnscachemanager.h"
#include "cmessagehandler.h"

__FLOG_STMT(_LIT8(KComponent,"MDNSServer");)


const TUint32 KMinActivityCount = 5;//TODO: to Define correct Min Work Count


/*
 * Two phase constructor
 * @param aActiveCacheMgmtEnabled
 * @param aMessageHandler reference to message handler.
 */
 CMDNSCacheConsistencyMgr* CMDNSCacheConsistencyMgr::NewL(TBool aActiveCacheMgmtEnabled,CMessageHandler& aMessageHandler)
	{
	CMDNSCacheConsistencyMgr* self = CMDNSCacheConsistencyMgr::NewLC(aActiveCacheMgmtEnabled,aMessageHandler);
	CleanupStack::Pop(self);
	return self;
	}

/*
 * Two phase constructor
 * @param aActiveCacheMgmtEnabled
 * @param aMessageHandler reference to message handler.
 */
CMDNSCacheConsistencyMgr* CMDNSCacheConsistencyMgr::NewLC(TBool aActiveCacheMgmtEnabled,CMessageHandler& aMessageHandler)
	{
	CMDNSCacheConsistencyMgr* self = new (ELeave)CMDNSCacheConsistencyMgr(aActiveCacheMgmtEnabled,aMessageHandler);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

/*
 * Constructor.
 */
CMDNSCacheConsistencyMgr::CMDNSCacheConsistencyMgr(TBool aActiveCacheMgmtEnabled,CMessageHandler& aMessageHandler)
:CActive(EPriorityStandard),iMessageHandler(aMessageHandler)
	{
	iActiveCacheMgmtEnabled=aActiveCacheMgmtEnabled;
	iWalkInterval= KDefaultCheckInterval;
	CActiveScheduler::Add(this);	
	}


//Destructor
CMDNSCacheConsistencyMgr::~CMDNSCacheConsistencyMgr()
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::~CMDNSCacheConsistencyMgr - Entry"));
	iTimer.Close();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::~CMDNSCacheConsistencyMgr - Exit"));
	__FLOG_CLOSE;
	}
/*
 * Two phase constructor
 */
void CMDNSCacheConsistencyMgr::ConstructL()
	{
	__FLOG_OPEN(KMDNSSubsystem, KComponent);
	__FLOG(_L8("CMDNSCacheConsistencyMgr::ConstructL - Entry"));
	User::LeaveIfError(iTimer.CreateLocal());	
	__FLOG(_L8("CMDNSCacheConsistencyMgr::ConstructL - Exit"));
	}

/*
 * Function to stop running the consistemcy manager .
 * Cancels all the asynchronous request.
 */
void CMDNSCacheConsistencyMgr::Stop()
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Stop - Entry"));
	Cancel();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Stop - Exit"));
	}
	
/*
 * Starts the consistency Manager
 * @param aWalkInterval specifies the walk interval in seconds.
 */	
void CMDNSCacheConsistencyMgr::Start(TUint aWalkInterval)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Start - Entry"));
	iWalkInterval = aWalkInterval;
	TUint Interval= iWalkInterval*1000000;
	//Converted to Microseconds		
	iTimer.After(iStatus,Interval);
	SetActive();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Start - Exit"));
	}
/*
 * Delay between two Walk thourgh .
 * Starts a time to complete the request after an interval mentioned in the iWalkinterval.
 * @param aStatus reference to status variable.
 */
 void CMDNSCacheConsistencyMgr::Delay(TRequestStatus& aStatus)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Delay - Entry"));
	TUint Interval= iWalkInterval*1000000;
	//Converted to Microseconds		
	iTimer.After(aStatus,Interval);
	SetActive();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Delay - Exit"));
	}


 /*
  * Iterates the cache on each hit
  * and sets a delay for the nexthit.
  */
void CMDNSCacheConsistencyMgr::RunL()
	{	
	__FLOG(_L8("CMDNSCacheConsistencyMgr::RunL - Entry"));
	IterateCacheL();
	Delay(iStatus);
	__FLOG(_L8("CMDNSCacheConsistencyMgr::RunL - Exit"));
	}

/*
 * Handles any leave at RunL
 * 
 */
TInt CMDNSCacheConsistencyMgr::RunError(TInt aError)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::RunError - Entry"));
	User::LeaveIfError(aError);
	return aError;
	__FLOG(_L8("CMDNSCacheConsistencyMgr::RunError - Exit"));
	}

/*
 * Cancels any asynchoronous request.
 */
void CMDNSCacheConsistencyMgr::DoCancel()
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::DoCancel - Entry"));
	iTimer.Cancel();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::DoCancel - Exit"));
	}
	
/*
 * Walk through the cache .Does two function
 * 1. Publish any authoritative entries.
 * 2. Query for the enteries if not authoritative.
 */
void CMDNSCacheConsistencyMgr::IterateCacheL()	
	{	
	__FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - Entry"));
	TBool iterateReset(ETrue);
	TBool cacheUpToDate(ETrue);
	TInt count = iMessageHandler.DnsCache().NumberOfEntries();
	TInt index(0);
	
	
		
	for(index=0; index<count;index++)
		{
		//Fetch the next entry whose ttl has completely expired or 80% 
		//of ttl has expired 
		CCacheEntry* entry = iMessageHandler.DnsCache().NextStaleEntry(iActiveCacheMgmtEnabled,iterateReset);

		//Reset the iterate flag
		iterateReset = EFalse;
	    __FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 1"));
		if(entry)
			{
			if(entry->EntryExpired())
				{
				
				if(entry->IsAuthoritative())
					{
					//Republish the record
					//Goodbye packet is sent while the session for publish is closed
					CDnsMessage * announcement = CDnsMessage::NewL(0,EFalse);
					CleanupStack::PushL(announcement);
					if(entry->PtrRecord())
					    {
                        entry->PtrRecord()->SetTtl(120);
					    announcement->AppendAnswerL(entry->PtrRecord()->CloneL());
					    iMessageHandler.DnsCache().UpdateCacheL(*(entry->PtrRecord()),ETrue,entry->SessionId());
                        __FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 2"));
					    }
					if(entry->ServiceRecord())
					    {
                        entry->ServiceRecord()->SetTtl(120);
					    announcement->AppendAnswerL(entry->ServiceRecord()->CloneL());
					    iMessageHandler.DnsCache().UpdateCacheL(*(entry->ServiceRecord()),ETrue,entry->SessionId());
					    __FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 3"));
					    }
					if(entry->TxtRecord())
					    {
                        entry->TxtRecord()->SetTtl(120);
					    announcement->AppendAnswerL(entry->TxtRecord()->CloneL());
					    iMessageHandler.DnsCache().UpdateCacheL(*(entry->TxtRecord()),ETrue,entry->SessionId());
					    __FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 4"));
					    }
					if(entry->AddressRecord())
                        {
                        entry->AddressRecord()->SetTtl(120);
                        announcement->AppendAnswerL(entry->AddressRecord()->CloneL());
                        iMessageHandler.DnsCache().UpdateCacheL(*(entry->AddressRecord()),ETrue,0);
                        __FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 5"));
                        }
					__FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 6"));
					iMessageHandler.SendQueryL(announcement,*this);
					__FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - 7"));
					CleanupStack::Pop();//announcement
					}
				else
				    {
	                if(!entry->IsAuthoritative())
	                    {
	                    DeleteEntry(entry);
	                    //Query(entry);
	                    }				    
				    }
				}
			cacheUpToDate = EFalse;
			}
		delete entry;
		}		
	__FLOG(_L8("CMDNSCacheConsistencyMgr::IterateCacheL - Exit"));	 
	}
	
/*
 * Delete the particular entry from the cache.
 * @param aEntry cacheentry to be delete.
 */	
void CMDNSCacheConsistencyMgr::DeleteEntry(CCacheEntry* aEntry)
	{	
	__FLOG(_L8("CMDNSCacheConsistencyMgr::DeleteEntry - Entry"));
	RBuf8 key;
	//Extract the key & delete
	
	if(aEntry->AddressRecord())
		{
		key.CreateL(GetHostName(aEntry));
		TInt delError = iMessageHandler.DnsCache().DeleteEntryL(key);//TODO: handle error
		}

	key.Close();
	key.CreateL(GetServiceName(aEntry));
	
	TInt error = iMessageHandler.DnsCache().DeleteEntryL(key);
	//Handle error
	key.Close();
	__FLOG(_L8("CMDNSCacheConsistencyMgr::DeleteEntry - Exit"));
	}
	
/*
 * Create a CDnsMessage object to be sent to the network using aEntry.
 *  
 */	
void CMDNSCacheConsistencyMgr::Query(CCacheEntry* aEntry)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Query - Entry"));
		//Construct DNS Message
	CDnsMessage* message = CDnsMessage::NewL(0,ETrue);
	CleanupStack::PushL(message);

	//Form the Query/Question part of the message
	CDnsQuestion* question = CDnsQuestion::NewL();
	CleanupStack::PushL(question);
	
	question->SetNameL(GetServiceName(aEntry));
	question->SetClass(EDnsClass_IN);
	question->SetType(EDnsQType_Any);

	//Append the Query to the Message
	message->AppendQueryL(question);
	if(aEntry->AddressRecord())
	message->AppendAnswerL(aEntry->AddressRecord()->CloneL());
	
	if(aEntry->ServiceRecord())
	message->AppendAnswerL(aEntry->ServiceRecord()->CloneL());
	
	if(aEntry->TxtRecord())
	message->AppendAnswerL(aEntry->TxtRecord()->CloneL());	
	
	if(aEntry->PtrRecord())
	message->AppendAnswerL(aEntry->PtrRecord()->CloneL());
	
	
		
	//Send the query
	iMessageHandler.SendQueryL(message,*this);		

	CleanupStack::Pop();//question
	CleanupStack::Pop();//message
	__FLOG(_L8("CMDNSCacheConsistencyMgr::Query - Exit"));
	}

/*
 * @return the hostname for the particular record.
 */	
const TDesC8& CMDNSCacheConsistencyMgr::GetHostName(CCacheEntry* aEntry)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::GetHostName - Entry Exit"));
	return aEntry->AddressRecord()->Name();
	}


/*
 * @param aEntry for which service name is required.
 * @return Domain name for the particular service.
 */
const TDesC8& CMDNSCacheConsistencyMgr::GetServiceName(CCacheEntry* aEntry)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::GetServiceName - Entry"));
	if(aEntry->ServiceRecord())
		{
		return aEntry->ServiceRecord()->Name();
		}
	else if (aEntry->TxtRecord())
		{
		return aEntry->TxtRecord()->Name();
		}
	else if(aEntry->PtrRecord())
		{
		return aEntry->PtrRecord()->DomainName();
		}
	else if(aEntry->AddressRecord())
	        {
	        return aEntry->AddressRecord()->Name();
	        }
	
	__FLOG(_L8("CMDNSCacheConsistencyMgr::GetServiceName - Exit"));
	}
	
/*
 * Notified for any queries sent .
 */	
void CMDNSCacheConsistencyMgr::OnPacketSendL(TInt /*aError*/)
	{
	__FLOG(_L8("CMDNSCacheConsistencyMgr::OnPacketSendL - Entry"));
	//Do nothing
	}
