meetingrequest/mrservices/src/cesmrconflictchecker.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 31 Mar 2010 21:08:33 +0300
branchRCL_3
changeset 33 da5135c61bad
child 29 6b8f3b30d0ec
permissions -rw-r--r--
Revision: 201011 Kit: 201013

/*
* Copyright (c) 2007-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 : ESMR conflict checker implementation
*  Version     : %version: e002sa33#7 %
*
*/

#include "emailtrace.h"
#include "cesmrconflictchecker.h"
#include "cesmrcaldbmgr.h"
#include "esmrhelper.h"
#include "esmrentryhelper.h"
#include "esmrinternaluid.h"

#include <calcommon.h>
#include <calinstance.h>
#include <calentryview.h>
#include <calinstanceview.h>
#include <calinstanceiterator.h>
#include <ct/rcpointerarray.h>

/// Unnamed namespace for local definitions
namespace { // codescanner::namespace

// Definition for zero
const TInt KZero(0);

/** Defines instace filter type */
enum TInstanceFilter
    {
    EIncludeSameUID,
    ERemoveSameUID
    };

#ifdef _DEBUG

// Literal for panic texts
_LIT( KESMRConflictCheckerTxt, "ESMRConflictChecker" );

/** Enumeration for panic codes */
enum TESMRConflictCheckerPanic
    {
    // Input entry is not appointment
    EESMRConflictCheckerInvalidEntryType
    };

/**
 * Thows system wide panic.
 * @param aPanic Panic code.
 */
void Panic( TESMRConflictCheckerPanic aPanic )
    {

    User::Panic( KESMRConflictCheckerTxt, aPanic );
    }

#else

/**
 * Thows system wide leave.
 * @param aError Leave code.
 */
void Leave( TInt aError )
    {

    User::Leave( aError );
    }

#endif

/**
 * Resolves time range for possible conflicting entries. Instance view
 * is used for resolving the time range.
 *
 * @param aStart Start time
 * @param aEnd End time
 * @param aInstanceView Pointer to calendar db instance view
 * @return Time range for possible conflicting entries
 */
CalCommon::TCalTimeRange ResolveFetchTimeRangeL(
        TTime aStart,
        TTime aEnd,
        CCalInstanceView* aInstanceView )
    {
    FUNC_LOG;
    const CalCommon::TCalViewFilter instanceFilter = 
            CalCommon::EIncludeAppts;

    TDateTime start = aStart.DateTime();
    TDateTime end   = aEnd.DateTime();

    start.SetHour( KZero );
    start.SetMinute( KZero );
    start.SetSecond( KZero );
    start.SetMicroSecond( KZero );

    end.SetHour( KZero );
    end.SetMinute( KZero );
    end.SetSecond( KZero );
    end.SetMicroSecond( KZero );
    TTime endTime = end;
    
    if ( TTime(start) == endTime || 
         endTime < aEnd )
        {
        
        endTime += TTimeIntervalDays(1);
        end = endTime.DateTime();
        }

    TCalTime rangeStart;
    rangeStart.SetTimeLocalL( start );

    TCalTime instanceTime = aInstanceView->PreviousInstanceL(
            instanceFilter,
            rangeStart );

    if (  Time::NullTTime() != instanceTime.TimeUtcL()  )
        {
        rangeStart = instanceTime;
        }

    TCalTime rangeEnd;
    rangeEnd.SetTimeLocalL( end );

    instanceTime = aInstanceView->NextInstanceL(
            instanceFilter,
            rangeEnd );

    if ( instanceTime.TimeLocalL() != Time::NullTTime() )
        {
        rangeEnd = instanceTime;
        }

    return CalCommon::TCalTimeRange( rangeStart, rangeEnd );
    }

/**
 * Removes and deletes the entries, which do not conflict with
 * entry. Entry is considered to be conflicting entry if starts or
 * ends between aEntry's start and end time.
 *
 * @param aEntries Reference to entries, which may conflict
 * @param aEntry Reference to entry, which confilcts are resolved.
 */
void RemoveAndDeleteNonConflictingInstancesL(
    RPointerArray<CCalInstance>& instanceArray,
    TCalTime aStartTime,
    TCalTime aEndTime,
    const TDesC8& aUid,
    TInstanceFilter aFilterType )
    {
    FUNC_LOG;
    TInt index(0);

    TTime startTimeLocal = aStartTime.TimeLocalL();
    TTime endTimeLocal = aEndTime.TimeLocalL();
    
    while( index < instanceArray.Count() )
        {
        TBool conflictingInstance( ETrue );
        CCalInstance* instance = instanceArray[index];
        
        TTime entryStartTimeLocal = instance->StartTimeL().TimeLocalL();
        TTime entryEndTimeLocal = instance->EndTimeL().TimeLocalL();            

        TPtrC8 uid( instance->Entry().UidL() );
        if ( ERemoveSameUID == aFilterType && 
             0 == aUid.CompareF(uid) )
            {
            conflictingInstance = EFalse;
            }
        else if ( entryStartTimeLocal >= startTimeLocal &&
                  entryStartTimeLocal < endTimeLocal )
            {
            // Entry starts during another entry
            index++;
            }
        else if ( entryEndTimeLocal > startTimeLocal &&
                entryEndTimeLocal <= endTimeLocal )
            {
            // Entry ends during another entry
            index++;
            }
        else if ( entryStartTimeLocal < startTimeLocal &&
                  entryEndTimeLocal > endTimeLocal )
            {
            // Antry starts and ends during another entry
            index++;
            }
        else
            {
            conflictingInstance = EFalse;            
            }
        
        // Remove non-conflicting instance from instance array
        if ( !conflictingInstance )
            {
            instanceArray.Remove(index);
            delete instance; 
            instance = NULL;
            }
        }
    }

/**
 * Creates calendar entries from the conflicting instances
 * and stores the created entries into entry array.
 * Ownership of the created entries is transferred to caller.
 * @param aInstanceArray Reference to instance array
 * @param aConflictingEntries Reference to entry array.
 */
void CreateEntriesFromInstancesL(
        RPointerArray<CCalInstance>& instanceArray,
        RPointerArray<CCalEntry>& aConflictingEntries )
    {
    FUNC_LOG;
    TInt instanceCount( instanceArray.Count() );    
    for ( TInt i(0); i < instanceCount; ++i )
        {        
        CCalEntry& parent( instanceArray[i]->Entry() );
        CCalEntry* entry = ESMRHelper::CopyEntryLC( parent, 
                                                    parent.MethodL(),
                                                    ESMRHelper::ECopyFull );
        
        entry->SetStartAndEndTimeL( instanceArray[i]->StartTimeL(),
                                    instanceArray[i]->EndTimeL() );

        User::LeaveIfError( aConflictingEntries.Append( entry ) );
        CleanupStack::Pop( entry );
        }
    }

}  // namespace

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CESMRConflictChecker::CESMRConflictChecker
// ---------------------------------------------------------------------------
//
inline CESMRConflictChecker::CESMRConflictChecker(
        MESMRCalDbMgr& aDbMgr ) :
        iDbMgr( aDbMgr )
    {
    FUNC_LOG;
    // Not implementation yet
    }

// ---------------------------------------------------------------------------
// CESMRConflictChecker::~CESMRConflictChecker
// ---------------------------------------------------------------------------
//
EXPORT_C CESMRConflictChecker::~CESMRConflictChecker()
    {
    FUNC_LOG;
    // Not implementation yet
    }

// ---------------------------------------------------------------------------
// CESMRConflictChecker::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CESMRConflictChecker* CESMRConflictChecker::NewL(
        MESMRCalDbMgr& aDbMgr )
    {
    FUNC_LOG;
    CESMRConflictChecker* self =
            new (ELeave) CESMRConflictChecker(aDbMgr);
    return self;
    }

// ---------------------------------------------------------------------------
// CESMRConflictChecker::FindConflictsL
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMRConflictChecker::FindConflictsL(
            const CCalEntry& aEntry,
            RPointerArray<CCalEntry>& aConflicts )
    {
    FUNC_LOG;

    // Checking input parameters
#ifdef _DEBUG

    __ASSERT_DEBUG(
            CCalEntry::EAppt == aEntry.EntryTypeL(),
            Panic(EESMRConflictCheckerInvalidEntryType) );

#else

    if ( CCalEntry::EAppt != aEntry.EntryTypeL() )
        {
        Leave( KErrArgument );
        }

#endif

    // Get instance views of all calendar
    RPointerArray<CCalInstanceView> allCalenInstanceView = 
                                    iDbMgr.NormalDbAllCalenInstanceView();
    
    RCPointerArray<CCalInstance> instanceArray;
    CleanupClosePushL( instanceArray );
    
    // Check if there is any conflict in each calendar
    for( TInt i = 0; i < allCalenInstanceView.Count(); i++ )
        {
        CalCommon::TCalTimeRange timeRange =
                    ResolveFetchTimeRangeL( 
                                    aEntry.StartTimeL().TimeUtcL(),
                                    aEntry.EndTimeL().TimeUtcL(), 
                                    allCalenInstanceView[i] );
        
        allCalenInstanceView[i]->FindInstanceL( instanceArray,
                                                CalCommon::EIncludeAppts,
                                                timeRange );


        }
    
    RemoveAndDeleteNonConflictingInstancesL(
                                    instanceArray,
                                    aEntry.StartTimeL(),
                                    aEntry.EndTimeL(),
                                    aEntry.UidL(),
                                    ERemoveSameUID );
    
    CreateEntriesFromInstancesL( instanceArray, aConflicts );
    CleanupStack::PopAndDestroy(); // instanceArray
    }

// ---------------------------------------------------------------------------
// CESMRConflictChecker::FindInstancesForEntry
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMRConflictChecker::FindInstancesForEntryL(
        TTime aStart, 
        TTime aEnd,
        const CCalEntry& aEntry,
        TCalCollectionId aColId, 
        RPointerArray<CCalEntry>& aInstances )
    {
    FUNC_LOG;
    CCalInstanceView* instanceView = iDbMgr.InstanceViewL( aEntry );

    RCPointerArray<CCalInstance> instanceArray;
    CleanupClosePushL( instanceArray );

    // First we need the parent entry of the series ...
    CCalInstance* entryInstance = instanceView->FindInstanceL( 
    		aEntry.LocalUidL(), 
    		aEntry.StartTimeL() ); //Ownership gained
    CleanupStack::PushL( entryInstance );

    CCalInstance* parentEntryInstance = instanceView->FindInstanceL( 
    		aEntry.LocalUidL(), 
    		entryInstance->Entry().StartTimeL() );
    CleanupStack::PopAndDestroy( entryInstance );
    CleanupStack::PushL( parentEntryInstance );
    
    // ... And the parent entry instances start time
    TCalTime firstIntanceStartTime( parentEntryInstance->StartTimeL() );

    CleanupStack::Pop( parentEntryInstance ); // ownership given to instanceArray
    instanceArray.Append( parentEntryInstance );

    // Let's get all instances which have same uid and collection id
    // as the aEntry to an iterator.
    CCalInstanceIterator* instanceIterator = instanceView->FindInstanceByUidL( 
    		aColId, 
    		aEntry.UidL(), 
    		firstIntanceStartTime );
    CleanupStack::PushL( instanceIterator );
    
    TInt count( instanceIterator->Count() );
    
    for( TInt i = 0; i < count; ++i )
    	{
		CCalInstance* instance = NULL;
		TRAPD( err, instance = instanceIterator->NextL() ); //Ownership gained
		if( !err && instance )
			{
			instanceArray.Append( instance );	
			}
    	}

    CleanupStack::PopAndDestroy( instanceIterator );

    // Now the instanceArray has all instances of the aEntry, 
    // let's remove this instance == instance of aEntry, from the array
	TInt i( 0 );
    while( i < instanceArray.Count() )
    	{
		CCalInstance* instance = instanceArray[i];
		
        TBool thisInstance( 
                instance->StartTimeL().TimeLocalL() == 
                aEntry.StartTimeL().TimeLocalL() &&
                instance->EndTimeL().TimeLocalL() == 
                aEntry.EndTimeL().TimeLocalL() );
        
        if( thisInstance )
        	{
			delete instance;
			instanceArray.Remove( i );  
        	}
        else
        	{
			++i;
        	}
    	}
  
    TCalTime start;
    start.SetTimeLocalL( aStart );
    
    TCalTime end;
    end.SetTimeLocalL( aEnd );

    RemoveAndDeleteNonConflictingInstancesL(
            instanceArray,
            start,
            end,
            aEntry.UidL(),
            EIncludeSameUID );
    
    CreateEntriesFromInstancesL( instanceArray, aInstances );
    
    CleanupStack::PopAndDestroy(); // instanceArray    
    }

// EOF