1/*
2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Oliver Tappe <zooey@hirschkaefer.de>
7 */
8
9
10#include <unicode/uversion.h>
11#include <DurationFormat.h>
12
13#include <new>
14
15#include <unicode/gregocal.h>
16#include <unicode/utypes.h>
17
18#include <Locale.h>
19#include <LocaleRoster.h>
20#include <TimeZone.h>
21
22#include <TimeZonePrivate.h>
23
24
25U_NAMESPACE_USE
26
27
28// maps our unit element to the corresponding ICU unit
29static const UCalendarDateFields skUnitMap[] = {
30	UCAL_YEAR,
31	UCAL_MONTH,
32	UCAL_WEEK_OF_MONTH,
33	UCAL_DAY_OF_WEEK,
34	UCAL_HOUR_OF_DAY,
35	UCAL_MINUTE,
36	UCAL_SECOND,
37};
38
39
40BDurationFormat::BDurationFormat(const BLanguage& language,
41	const BFormattingConventions& conventions,
42	const BString& separator, const time_unit_style style)
43	:
44	Inherited(language, conventions),
45	fSeparator(separator),
46	fTimeUnitFormat(language, conventions, style)
47{
48	UErrorCode icuStatus = U_ZERO_ERROR;
49	fCalendar = new GregorianCalendar(icuStatus);
50	if (fCalendar == NULL) {
51		fInitStatus = B_NO_MEMORY;
52		return;
53	}
54}
55
56
57BDurationFormat::BDurationFormat(const BString& separator,
58	const time_unit_style style)
59	:
60	Inherited(),
61	fSeparator(separator),
62	fTimeUnitFormat(style)
63{
64	UErrorCode icuStatus = U_ZERO_ERROR;
65	fCalendar = new GregorianCalendar(icuStatus);
66	if (fCalendar == NULL) {
67		fInitStatus = B_NO_MEMORY;
68		return;
69	}
70}
71
72
73BDurationFormat::BDurationFormat(const BDurationFormat& other)
74	:
75	Inherited(other),
76	fSeparator(other.fSeparator),
77	fTimeUnitFormat(other.fTimeUnitFormat),
78	fCalendar(other.fCalendar != NULL
79		? new GregorianCalendar(*other.fCalendar) : NULL)
80{
81	if (fCalendar == NULL && other.fCalendar != NULL)
82		fInitStatus = B_NO_MEMORY;
83}
84
85
86BDurationFormat::~BDurationFormat()
87{
88	delete fCalendar;
89}
90
91
92void
93BDurationFormat::SetSeparator(const BString& separator)
94{
95	fSeparator = separator;
96}
97
98
99status_t
100BDurationFormat::SetTimeZone(const BTimeZone* timeZone)
101{
102	if (fCalendar == NULL)
103		return B_NO_INIT;
104
105	BTimeZone::Private zonePrivate;
106	if (timeZone == NULL) {
107		BTimeZone defaultTimeZone;
108		status_t result
109			= BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone);
110		if (result != B_OK)
111			return result;
112		zonePrivate.SetTo(&defaultTimeZone);
113	} else
114		zonePrivate.SetTo(timeZone);
115
116	TimeZone* icuTimeZone = zonePrivate.ICUTimeZone();
117	if (icuTimeZone != NULL)
118		fCalendar->setTimeZone(*icuTimeZone);
119
120	return B_OK;
121}
122
123
124status_t
125BDurationFormat::Format(BString& buffer, const bigtime_t startValue,
126	const bigtime_t stopValue) const
127{
128	UErrorCode icuStatus = U_ZERO_ERROR;
129	fCalendar->setTime((UDate)startValue / 1000, icuStatus);
130	if (!U_SUCCESS(icuStatus))
131		return B_ERROR;
132
133	UDate stop = (UDate)stopValue / 1000;
134	bool needSeparator = false;
135	for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) {
136		int delta
137			= fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus);
138		if (!U_SUCCESS(icuStatus))
139			return B_ERROR;
140
141		if (delta != 0) {
142			if (needSeparator)
143				buffer.Append(fSeparator);
144			else
145				needSeparator = true;
146			status_t status = fTimeUnitFormat.Format(buffer, delta,
147				(time_unit_element)unit);
148			if (status != B_OK)
149				return status;
150		}
151	}
152
153	return B_OK;
154}
155