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