calendarui/editors/src/KoreanLunarDateUtil.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 14 Sep 2010 21:17:03 +0300
branchRCL_3
changeset 31 97232defd20e
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2010 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 "KoreanLunarDateUtil.h"
// debug
#include "calendarui_debug.h"

const TInt KMaxLunarYear = 60;

/**
 * Public methods for constructing a CKoreanLunarDateUtil object.
 */
CKoreanLunarDateUtil* CKoreanLunarDateUtil::NewL(MCalenServices* aServices)
    {
    TRACE_ENTRY_POINT;
    CKoreanLunarDateUtil* self = CKoreanLunarDateUtil::NewLC(aServices);
    CleanupStack::Pop( self );
    
    TRACE_EXIT_POINT;
    return self;
    }

CKoreanLunarDateUtil* CKoreanLunarDateUtil::NewLC(MCalenServices* aServices)
    {
    TRACE_ENTRY_POINT;
    CKoreanLunarDateUtil* self = new (ELeave) CKoreanLunarDateUtil(aServices);
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


CKoreanLunarDateUtil::CKoreanLunarDateUtil(MCalenServices* aServices):iServices(aServices)
	{
    TRACE_ENTRY_POINT;
	}


void CKoreanLunarDateUtil::ConstructL()
	{
    TRACE_ENTRY_POINT;
    iConverter = CKoreanCalConv::NewL();
	}

CKoreanLunarDateUtil::~CKoreanLunarDateUtil()
    {
    TRACE_ENTRY_POINT;
    delete iConverter;
    }

/**
 * Method for getting nearest gregorian date from
 * lunar day and month and gregorian reference.
 */
TDateTime CKoreanLunarDateUtil::GetNearestGregorianDateL( const TInt aMonth,
                                                          const TInt aDay,
                                                          const TBool aLeap,
                                                          const TDateTime& aReference ) const
	{
    TRACE_ENTRY_POINT;
    TKoreanDate refLunarDate;
    TKoreanDate lunarDate;
    TDateTime resDateTime;
    TInt err = KErrNone;

    iConverter->DateTimeToKoreanL( aReference, refLunarDate );
    /* Try to convert with the year and cycle we got with the reference */
    lunarDate.iCycle = refLunarDate.iCycle;
    lunarDate.iYear = refLunarDate.iYear;
    lunarDate.iMonth = aMonth;
    lunarDate.iDay = aDay;
    lunarDate.iLeapMonth = aLeap;
    TRAP( err, iConverter->KoreanToDateTimeL( lunarDate, resDateTime ) );
    if( err == KErrArgument )
        { /* Date is invalid for this year (day 30 on a month
             that has only 29 days on selected year or a leap month
             not in this year), try to find suitable */
        TKoreanDate lowerLimit;
        TKoreanDate upperLimit;
        iConverter->DateRange( lowerLimit, upperLimit );
        while( 1 )
            { /* Search by increasing year */
            if( lunarDate.iYear < KMaxLunarYear )
               {
                lunarDate.iYear++;
                }
            else
                {
                lunarDate.iYear = 1;
                lunarDate.iCycle++;
                }
            if( (lunarDate.iCycle == upperLimit.iCycle &&
                 lunarDate.iYear > upperLimit.iYear)  ||
                lunarDate.iCycle > upperLimit.iCycle )
                { /* Could not find, just break */
                break;
                }
            TRAP( err, iConverter->KoreanToDateTimeL( lunarDate, resDateTime ) );
            if( err == KErrNone )
                { /* Found suitable */
                break;
                }
            }
        if( err != KErrNone )
            { /* Suitable not found by increasing,
                 reset values and search by decreasing year */
            lunarDate.iCycle = refLunarDate.iCycle;
            lunarDate.iYear = refLunarDate.iYear;
            lunarDate.iMonth = aMonth;
            lunarDate.iDay = aDay;
            while( 1 )
                { /* Search by decreasing year */
                if( lunarDate.iYear > 1 )
                   {
                    lunarDate.iYear--;
                    }
                else
                    {
                    if( lunarDate.iCycle == 0 )
                        { /* Run out of cycles, break with error */
                        break;
                        }
                    lunarDate.iYear = KMaxLunarYear;
                    lunarDate.iCycle--;
                    }
                if( (lunarDate.iCycle == lowerLimit.iCycle &&
                     lunarDate.iYear < lowerLimit.iYear)  ||
                    lunarDate.iCycle < lowerLimit.iCycle )
                    { /* Could not find, just break */
                    break;
                    }
                TRAP( err, iConverter->KoreanToDateTimeL( lunarDate, resDateTime ) );
                if( err == KErrNone )
                    { /* Found suitable */
                    break;
                    }
                }
            }
        }
    /* If still not found, leave with error */
    User::LeaveIfError( err );
    
    TRACE_ENTRY_POINT;
    /* Otherwise return the result */
    return resDateTime;
	}

/**
* Method for getting lunar yearly repeats in gregorian dates.
*/
void CKoreanLunarDateUtil::GetLunarYearlyRepeatsL( RArray<TCalTime>& aRDates,
                                                   const TDateTime& aEntryDate,
                                                   const TBool aFloating ) const
    {
    TInt err = KErrNone;
    TCalTime repeatDate;
    TDateTime resDateTime;
    TDateTime lowerLimit;
    TKoreanDate upperKoreanLimit;
    TKoreanDate lunarStartDate;
    
    /* Get the upper limit for dates in Korean lunar format */
    iConverter->DateRange( lunarStartDate, upperKoreanLimit );
    
    /* Get the entry date in Korean lunar format */
    iConverter->DateTimeToKoreanL( aEntryDate, lunarStartDate );
    
    /* Get the lower limit for dates in Gregorian format */
    iConverter->DateRange( lowerLimit, resDateTime );
    
    /* Get the first occurrence of the event after
    the lower limit in Korean lunar format */
    iConverter->DateTimeToKoreanL(  GetNearestGregorianDateL( lunarStartDate.iMonth,
                                  lunarStartDate.iDay,
                                  lunarStartDate.iLeapMonth,
                                  lowerLimit ),
                                  lunarStartDate );
    
    while( 1 )
        {
        TRAP( err, iConverter->KoreanToDateTimeL( lunarStartDate, resDateTime ) );
        if( err == KErrNone )
            { /* Date exists in current year */
            if( aFloating )
                {
                repeatDate.SetTimeLocalFloatingL( resDateTime );
                }
            else
                {
                repeatDate.SetTimeLocalL( resDateTime );
                }
            aRDates.AppendL( repeatDate );
            }
        /* Increase to next lunar year */
        if( lunarStartDate.iYear < KMaxLunarYear )
            {
            lunarStartDate.iYear++;
            }
        else
            {
            lunarStartDate.iYear = 1;
            lunarStartDate.iCycle++;
            }
        if( (lunarStartDate.iCycle == upperKoreanLimit.iCycle &&
                lunarStartDate.iYear > upperKoreanLimit.iYear)  ||
                lunarStartDate.iCycle > upperKoreanLimit.iCycle )
            { /* Reached the limit, break */
            break;
            }
        }
    }
    
// End of file