meetingrequest/mrentry/src/cesmrconflictchecker.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:39:21 +0200
changeset 0 8466d47a6819
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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: tr1sido#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 <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 confilct 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,    
    // const CCalEntry& aEntry,
    TCalTime aStartTime,
    TCalTime aEndTime,
    const TDesC8& aUid,
    TInstanceFilter aFilterType )
    {
    FUNC_LOG;
    TInt index(0);

    TTime startTimeUtc = aStartTime.TimeUtcL();
    TTime endTimeUtc = aEndTime.TimeUtcL();
    
    while( index < instanceArray.Count() )
        {
        TBool conflictingInstance( ETrue );
        CCalInstance* instance = instanceArray[index];
        
        TTime entryStartTimeUtc = instance->StartTimeL().TimeUtcL();
        TTime entryEndTimeUtc = instance->EndTimeL().TimeUtcL();            

        TPtrC8 uid( instance->Entry().UidL() );
        if ( ERemoveSameUID == aFilterType && 
             0 == aUid.CompareF(uid) )
            {
            conflictingInstance = EFalse;
            }
        else if ( entryStartTimeUtc >= startTimeUtc &&
                  entryStartTimeUtc < endTimeUtc )
            {
            // Entry starts during another entry
            index++;
            }
        else if ( entryEndTimeUtc > startTimeUtc &&
                entryEndTimeUtc <= endTimeUtc )
            {
            // Entry ends during another entry
            index++;
            }
        else if ( entryStartTimeUtc > startTimeUtc &&
                  entryEndTimeUtc < endTimeUtc )
            {
            // Antry starts and ends during another entry
            index++;
            }
        else if ( entryStartTimeUtc < startTimeUtc &&
                  entryEndTimeUtc > endTimeUtc )
            {
            // 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
// ---------------------------------------------------------------------------
//
CESMRConflictChecker::~CESMRConflictChecker()
    {
    FUNC_LOG;
    // Not implementation yet
    }

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

// ---------------------------------------------------------------------------
// CESMRConflictChecker::FindConflictsL
// ---------------------------------------------------------------------------
//
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

    CCalInstanceView* instanceView = iDbMgr.NormalDbInstanceView();
    
    CalCommon::TCalTimeRange timeRange =
            ResolveFetchTimeRangeL( 
                    aEntry.StartTimeL().TimeUtcL(),
                    aEntry.EndTimeL().TimeUtcL(), 
                    instanceView );

    RCPointerArray<CCalInstance> instanceArray;
    CleanupClosePushL( instanceArray );

    instanceView->FindInstanceL( instanceArray,
                                 CalCommon::EIncludeAppts,
                                 timeRange );

    RemoveAndDeleteNonConflictingInstancesL(
            instanceArray,
            aEntry.StartTimeL(),
            aEntry.EndTimeL(),
            aEntry.UidL(),
            ERemoveSameUID );

    CreateEntriesFromInstancesL( instanceArray, aConflicts );
    
    CleanupStack::PopAndDestroy(); // instanceArray
    
    }

// ---------------------------------------------------------------------------
// CESMRConflictChecker::FindInstancesForEntry
// ---------------------------------------------------------------------------
//
void CESMRConflictChecker::FindInstancesForEntryL(
        TTime aStart, 
        TTime aEnd,
        const CCalEntry& aEntry,
        RPointerArray<CCalEntry>& aInstances )
    {
    FUNC_LOG;
    TDateTime startDt = aStart.DateTime();
    startDt.SetHour( KZero );
    startDt.SetMinute( KZero );
    startDt.SetSecond( KZero );
    
    TDateTime endDt = aEnd.DateTime();
    endDt.SetHour( KMaxHoursInDay );
    endDt.SetMinute( KMaxMinutesInHour );
    endDt.SetSecond( KMaxSecondsInMinute );
    
    aStart = startDt;
    aEnd = endDt;
    
    CCalInstanceView* instanceView = iDbMgr.NormalDbInstanceView();
    
    CalCommon::TCalTimeRange timeRange =
            ResolveFetchTimeRangeL( 
                    aStart,
                    aEnd, 
                    instanceView );

    RCPointerArray<CCalInstance> instanceArray;
    CleanupClosePushL( instanceArray );

    instanceView->FindInstanceL( instanceArray,
                                 CalCommon::EIncludeAppts,
                                 timeRange );
    
    TInt i(0);
    while( i < instanceArray.Count() )
        {
        CCalInstance* instance = instanceArray[i];
        CCalEntry& instanceEntry( instance->Entry() );
        
        TBool sameUid( 
                0 == instanceEntry.UidL().CompareF( aEntry.UidL() ) );
        
        TBool thisInstance( 
                instance->StartTimeL().TimeLocalL() == 
                aEntry.StartTimeL().TimeLocalL() &&
                instance->EndTimeL().TimeLocalL() == 
                aEntry.EndTimeL().TimeLocalL() );      
        
        if ( !sameUid || thisInstance )
            {
            // This is either same entry as aEntry or then
            // this entry does not belong to this series 
            delete instance;
            instanceArray.Remove( i );            
            }
        else
            {
            ++i;
            }        
        }
    
    TCalTime start;
    start.SetTimeUtcL( aStart );
    
    TCalTime end;
    end.SetTimeUtcL( aEnd );
    
    RemoveAndDeleteNonConflictingInstancesL(
            instanceArray,
            start,
            end,
            aEntry.UidL(),
            EIncludeSameUID );
    
    CreateEntriesFromInstancesL( instanceArray, aInstances );
    
    CleanupStack::PopAndDestroy(); // instanceArray    
    }

// EOF