/*
 * Copyright 2010, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Oliver Tappe <zooey@hirschkaefer.de>
 */


#ifndef HoG_GENODE
#include <unicode/uversion.h>
#else
#	include <stdio.h>  // sprintf()
#endif  // HoG_GENODE
#include <DurationFormat.h>

#include <new>

#ifndef HoG_GENODE
#include <unicode/gregocal.h>
#include <unicode/utypes.h>
#endif  // ~HoG_GENODE

#include <Locale.h>
#include <LocaleRoster.h>
#include <TimeZone.h>

#ifndef HoG_GENODE
#include <TimeZonePrivate.h>


// maps our unit element to the corresponding ICU unit
static const UCalendarDateFields skUnitMap[] = {
	UCAL_YEAR,
	UCAL_MONTH,
	UCAL_WEEK_OF_MONTH,
	UCAL_DAY_OF_WEEK,
	UCAL_HOUR_OF_DAY,
	UCAL_MINUTE,
	UCAL_SECOND,
};
#endif  // ~HoG_GENODE


#ifndef HoG_GENODE
BDurationFormat::BDurationFormat(const BLanguage& language,
	const BFormattingConventions& conventions,
	const BString& separator, const time_unit_style style)
	:
	Inherited(language, conventions),
	fSeparator(separator),
	fTimeUnitFormat(language, conventions, style)
{
	UErrorCode icuStatus = U_ZERO_ERROR;
	fCalendar = new GregorianCalendar(icuStatus);
	if (fCalendar == NULL) {
		fInitStatus = B_NO_MEMORY;
		return;
	}
}
#endif  // ~HoG_GENODE


BDurationFormat::BDurationFormat(const BString& separator,
	const time_unit_style style)
	:
	Inherited(),
	fSeparator(separator),
	fTimeUnitFormat(style)
{
#ifndef HoG_GENODE
	UErrorCode icuStatus = U_ZERO_ERROR;
	fCalendar = new GregorianCalendar(icuStatus);
	if (fCalendar == NULL) {
		fInitStatus = B_NO_MEMORY;
		return;
	}
#endif  // ~HoG_GENODE
}


#ifndef HoG_GENODE
BDurationFormat::BDurationFormat(const BDurationFormat& other)
	:
	Inherited(other),
	fSeparator(other.fSeparator),
	fTimeUnitFormat(other.fTimeUnitFormat),
	fCalendar(other.fCalendar != NULL
		? new GregorianCalendar(*other.fCalendar) : NULL)
{
	if (fCalendar == NULL && other.fCalendar != NULL)
		fInitStatus = B_NO_MEMORY;
}
#endif  // ~HoG_GENODE


BDurationFormat::~BDurationFormat()
{
#ifndef HoG_GENODE
	delete fCalendar;
#endif  // ~HoG_GENODE
}


#ifndef HoG_GENODE
void
BDurationFormat::SetSeparator(const BString& separator)
{
	fSeparator = separator;
}


status_t
BDurationFormat::SetTimeZone(const BTimeZone* timeZone)
{
	if (fCalendar == NULL)
		return B_NO_INIT;

	BTimeZone::Private zonePrivate;
	if (timeZone == NULL) {
		BTimeZone defaultTimeZone;
		status_t result
			= BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone);
		if (result != B_OK)
			return result;
		zonePrivate.SetTo(&defaultTimeZone);
	} else
		zonePrivate.SetTo(timeZone);

	TimeZone* icuTimeZone = zonePrivate.ICUTimeZone();
	if (icuTimeZone != NULL)
		fCalendar->setTimeZone(*icuTimeZone);

	return B_OK;
}
#endif  // ~HoG_GENODE


status_t
BDurationFormat::Format(BString& buffer, const bigtime_t startValue,
	const bigtime_t stopValue) const
{
#ifndef HoG_GENODE
	UErrorCode icuStatus = U_ZERO_ERROR;
	fCalendar->setTime((UDate)startValue / 1000, icuStatus);
	if (!U_SUCCESS(icuStatus))
		return B_ERROR;

	UDate stop = (UDate)stopValue / 1000;
	bool needSeparator = false;
	for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) {
		int delta
			= fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus);
		if (!U_SUCCESS(icuStatus))
			return B_ERROR;

		if (delta != 0) {
			if (needSeparator)
				buffer.Append(fSeparator);
			else
				needSeparator = true;
			status_t status = fTimeUnitFormat.Format(buffer, delta,
				(time_unit_element)unit);
			if (status != B_OK)
				return status;
		}
	}

#else

	char buf[64] = {};
	{
		long duration = stopValue;
		duration -= startValue;
		duration /= 1000000LL;
		
///later: duration format (for Tracker ?)
		sprintf( buf, "%ld Seconds", duration );
	}
	buffer = buf;
#endif  // ~HoG_GENODE

	return B_OK;
}
