pimappsupport/chinesecalendaralg/pluginsrc/chinesecalendar.cpp
branchRCL_3
changeset 10 38571fd2a704
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappsupport/chinesecalendaralg/pluginsrc/chinesecalendar.cpp	Fri Mar 12 15:42:35 2010 +0200
@@ -0,0 +1,368 @@
+// Copyright (c) 2000-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:
+// Implementation of the TChineseCalendar class.
+//
+
+#include "chinesecalendar.h"
+#include "arithmeticaldate.h"
+#include "gregoriancalendar.h"
+
+#if defined(_DEBUG)
+_LIT(KCalconPanic,"Calcon");
+#endif
+
+const TUint KMonthInvalid=0;
+const TUint K29DayMonth=1;
+const TUint K30DayMonth=2;
+const TUint K29DayLeapMonth=3;
+const TUint K30DayLeapMonth=4;
+
+const TUint KMonthMask=1<<15;
+const TUint KLeapMonthShift=28;
+
+const TInt KNoOfYearsInCycle = 60;
+
+enum TCalconPanic
+	{
+	ECalconChineseFromFixedMonthInvalid=0,
+	ECalconChineseToFixedLeapYearInvalid,
+	ECalconGetDataYearOutOfRange,
+	ECalconGetDataMonthOutOfRange,
+	ECalconGetNewYearYearOutOfRange
+	};
+
+TUint TCalconData::GetData(TInt aCycle, TInt aYear, TInt aMonth) const
+	{
+	__ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetDataYearOutOfRange));	//year range is 0..59
+	__ASSERT_DEBUG((aMonth>=0 && aMonth<=12), User::Panic(_L("Calcon"), ECalconGetDataMonthOutOfRange));//month range is 0..12
+
+	TInt y=(aCycle*KNoOfYearsInCycle)+aYear;
+	y-=(KFirstYear-1);	//there are KFirstYear-1 entries missing from the head of the table
+	TUint16 x=iCalConDataMonth[y];
+
+	TUint mask=KMonthMask>>aMonth;
+	
+	TInt flag=K29DayMonth;
+	if (x & mask)
+		flag=K30DayMonth;
+
+	TUint leapMonth=iCalConDataYear[y]>>KLeapMonthShift;
+	leapMonth--;
+
+	if ((TUint)aMonth==leapMonth)
+		flag+=2;	//--> K29/30DayLeapMonth
+	
+	if ((aMonth==12) && (leapMonth==0))
+		flag=KMonthInvalid;//month doesn't exist
+
+	return flag;
+	}
+
+TUint TCalconData::GetNewYear(TInt aCycle, TInt aYear) const
+	{
+	__ASSERT_DEBUG((aYear>=0 && aYear<=59), User::Panic(_L("Calcon"), ECalconGetNewYearYearOutOfRange));
+	TInt y=(aCycle*KNoOfYearsInCycle)+aYear;
+	y-=(KFirstYear-1);
+	return (iCalConDataYear[y] & 0x0fffffff);
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseToDateTime
+// Arguments:   TDateTime &
+//
+// Comments:    This function converts the date held within
+//				the TChineseCalendar class to a TDateTime format and 
+//				places it in the TDateTime class provided.
+//
+// Return:      void
+//------------------------------------------------------
+void TChineseCalendar::ChineseToDateTime(TDateTime &aDT)
+	{
+	TArithmeticalDate gregDate;
+	TGregorianCalendar greg(iJulianDay);
+
+	greg.GregFromJulianDay(gregDate,iJulianDay);
+	aDT.Set(0,EJanuary,0,0,0,0,0);
+
+	aDT.SetDay(gregDate.iDay - KCalConvMonthOffsetByOne);
+	aDT.SetMonth((TMonth)(gregDate.iMonth - KCalConvMonthOffsetByOne));
+	aDT.SetYear(gregDate.iYear);
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    DateTimeToChinese
+// Arguments:   TDateTime &
+//
+// Comments:    Sets the date held in the given TDateTime
+//				class to the TChineseCalendar class
+//
+// Return:      void
+//------------------------------------------------------
+void TChineseCalendar::DateTimeToChinese(const TDateTime &aDT)
+	{
+	TArithmeticalDate gregDate;
+	TGregorianCalendar greg;
+
+	gregDate.iDay = aDT.Day() + KCalConvMonthOffsetByOne;
+	gregDate.iMonth = (TInt)aDT.Month() + KCalConvMonthOffsetByOne;
+	gregDate.iYear = aDT.Year();
+
+	iJulianDay = greg.GregToJulianDay(gregDate);
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    SetDate
+// Arguments:   TChineseDate&
+//
+// Comments:    this function sets the julian day value
+//				in the base class from the given 
+//				TChineseDate
+//
+// Return:      None
+//------------------------------------------------------
+TInt TChineseCalendar::SetDate(const TChineseDate &aDate)
+	{
+	TReal jD;
+	TChineseDate ChinDate = aDate;
+	
+	if(!ValidDate(ChinDate))
+		return KErrArgument;
+	
+	if (!ChineseToFixed(aDate,jD))
+		return KErrArgument;
+
+	if (jD<KFirstJulianDate || jD>KLastJulianDate)
+		return KErrArgument;
+
+	iJulianDay = (TInt)jD;
+	return KErrNone;
+	}
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    GetDate
+// Arguments:   TChineseDate &
+//
+// Comments:    This function Determines the chinese date and 
+//				places it in the TChineseDate class provided
+//				for the julian day value held internally in the 
+//				Chinese class.
+//
+// Return:      None
+//------------------------------------------------------
+TInt TChineseCalendar::GetDate(TChineseDate &aDate)
+	{
+	return ChineseFromFixed(aDate,iJulianDay);
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseToFixed
+// Arguments:   TChineseDate , TReal &
+//				TChineseDate members start at 1 (not zero)
+//
+// Comments:    This function converts a chinese date to 
+//				to a julian day value.
+//
+// Return:      TBool ETrue if date valid, else EFalse
+//------------------------------------------------------
+TBool TChineseCalendar::ChineseToFixed(const TChineseDate& aDate, TReal &aJulianDay) const
+	{
+	TInt cycle=aDate.iCycle-KFirstCycle;	//cycle starts from zero
+	TInt year=aDate.iYear-1;				//year is 0..59
+
+	TInt days=0;
+
+	TInt targetMonth=aDate.iMonth;			//targetMonth is 1..12
+	TBool leap=aDate.iLeapMonth;
+	if (leap)
+		{
+		targetMonth++;
+		if (iData.GetData(cycle, year, targetMonth-1)<3)
+			return EFalse;	//not a leap month
+		}
+
+	TInt month=1;
+	while (month<=targetMonth)
+		{
+		TInt daysFlag=iData.GetData(cycle, year, month-1);
+		
+//We need to handle case where targetMonth is a leap month
+//Eg if Chinese month==6 targetMonth will be 6
+//Eg but if Chinese month 5 is a leap month, month 6 will be 5(leap) so we need to take it into account
+//BUT Eg if Chinese momth== 7(leap) we've already taken this into account.
+		if (month==targetMonth)	
+			if ((leap) || (daysFlag<3))
+				break;
+
+		switch (daysFlag)
+			{
+			case KMonthInvalid:
+				return EFalse;
+			case K29DayMonth:
+				days+=29;
+				break;
+			case K30DayMonth:
+				days+=30;
+				break;
+			case K29DayLeapMonth:
+				__ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid));
+				leap=ETrue;
+				targetMonth++;
+				days+=29;
+				break;
+			case K30DayLeapMonth:
+				__ASSERT_DEBUG(!leap, User::Panic(KCalconPanic,ECalconChineseToFixedLeapYearInvalid));
+				leap=ETrue;
+				targetMonth++;
+				days+=30;
+				break;
+			}
+		month++;
+		}
+
+//Check that if days==30, the requested month actually has 30 days
+	TInt checkMonth = aDate.iMonth;
+	if (leap)
+		checkMonth++;	//this is the month requested by the user
+	TUint daysFlag=iData.GetData(cycle, year, checkMonth-1);
+
+	if ((aDate.iDay==30) && ((daysFlag==K29DayMonth) || (daysFlag==K29DayLeapMonth)))
+		return EFalse;
+
+	days+=aDate.iDay-1;
+	
+	days+=iData.GetNewYear(cycle, year);//add the New Year
+	aJulianDay=days;
+	return ETrue;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ChineseFromFixed
+// Arguments:   TChineseDate &, TReal
+//
+// Comments:    this function converts a julian day value to
+//				a chinese date in the form TChineseDate
+//
+// Return:      None
+//------------------------------------------------------
+TInt TChineseCalendar::ChineseFromFixed(TChineseDate &aDate, const TReal& aJulianDay) const
+	{
+	if ((aJulianDay<KFirstJulianDate)
+		|| (aJulianDay>KLastJulianDate))
+		return KErrArgument;
+
+	TInt cycleIndex=0;
+
+	while ((cycleIndex < KLastCycle-KFirstCycle) 
+			&& (aJulianDay >= iData.GetNewYear(cycleIndex+1,0)))
+		cycleIndex++;
+	
+	aDate.iCycle=cycleIndex + KFirstCycle;
+	TInt chineseNewYear;
+	TInt yearCount=0;
+	if (cycleIndex==0)
+		yearCount=KFirstYear-1;
+
+	while (yearCount<60 && aJulianDay >= iData.GetNewYear(cycleIndex,yearCount))
+		yearCount++;
+		
+	aDate.iYear=yearCount;
+	chineseNewYear = iData.GetNewYear(cycleIndex,--yearCount);
+	
+	TInt addedNumberOfDays = 0;
+	TInt previousAddedNumberOfDays = 0;
+	TInt monthCount = 1;
+	aDate.iMonth = 0;
+
+	TInt monthNumber; // 0=No month exists, 1 = 29 day month, 2 = 30 day month, 3 = 29 day leap month, 4 = 30 day leap month
+
+	while (aJulianDay >= (chineseNewYear + addedNumberOfDays))
+		{
+		previousAddedNumberOfDays = addedNumberOfDays;
+		monthNumber = iData.GetData(cycleIndex,yearCount,monthCount-1);
+
+		switch (monthNumber)
+			{
+		case KMonthInvalid:
+			__ASSERT_DEBUG(0, User::Panic(_L("Calcon"),ECalconChineseFromFixedMonthInvalid));
+			break;
+		case K29DayMonth:
+			addedNumberOfDays += 29;
+			aDate.iMonth++;
+			aDate.iLeapMonth = EFalse;
+			break;
+		case K30DayMonth:
+			addedNumberOfDays += 30;
+			aDate.iMonth++;
+			aDate.iLeapMonth = EFalse;
+			break;
+		case K29DayLeapMonth:
+			addedNumberOfDays += 29;
+			aDate.iLeapMonth = ETrue;
+			break;
+		case K30DayLeapMonth:
+			addedNumberOfDays += 30;
+			aDate.iLeapMonth = ETrue;
+			break;
+			}
+		monthCount++;
+		}
+
+	aDate.iDay = (TInt)aJulianDay - chineseNewYear-previousAddedNumberOfDays;
+	aDate.iDay++;
+	return KErrNone;
+	}
+
+//------------------------------------------------------
+// Class:       TChineseCalendar
+// Function:    ValidDate
+// Arguments:   TChineseDate &
+//
+// Comments:    This function Determines whether the given
+//				date is a valid chinese date
+//
+// Return:      TBool - ETrue if date is valid, else EFalse
+//------------------------------------------------------
+TBool TChineseCalendar::ValidDate(const TChineseDate &aDate) const
+	{
+	//do some trivial checks to ensure that the date is in the range of the lookup table
+	if (aDate.iYear==0 || aDate.iYear>KNoOfYearsInCycle)
+		return EFalse;
+
+	if (aDate.iCycle < KFirstCycle)
+		return EFalse;
+
+	if (aDate.iCycle==KFirstCycle && aDate.iYear < KFirstYear)
+		return EFalse;
+	
+	if (aDate.iCycle > KLastCycle)
+		return EFalse;
+
+	if ( (aDate.iCycle==KLastCycle) && (aDate.iYear>KLastYear))
+		return EFalse;
+
+	if (aDate.iDay==0 || aDate.iDay>30)
+		return EFalse;
+
+	return ETrue;
+	}
+
+TReal TChineseCalendar::JulianDate() __SOFTFP
+	{
+	return iJulianDay;
+	}