/*
 * Copyright 2014-2015 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Adrien Destugues, pulkomandy@pulkomandy.tk
 *		John Scipione, jscipione@gmail.com
 */

#ifndef HoG_GENODE
#include <unicode/uversion.h>
#else
#	include <stdio.h>  // sprintf()
#	include <support/StringList.h>
#endif  // ~HoG_GENODE
#include <StringFormat.h>

#include <Autolock.h>
#include <FormattingConventionsPrivate.h>
#include <LanguagePrivate.h>

#ifndef HoG_GENODE
#include <ICUWrapper.h>

#include <unicode/msgfmt.h>
#endif  // ~HoG_GENODE


#ifndef HoG_GENODE
BStringFormat::BStringFormat(const BLanguage& language, const BString pattern)
	: BFormat(language, BFormattingConventions())
{
	_Initialize(UnicodeString::fromUTF8(pattern.String()));
}
#endif  // ~HoG_GENODE


BStringFormat::BStringFormat(const BString pattern)
	: BFormat()
{
#if defined( HoG_GENODE )
	formatPattern = pattern;

#else  // upstream:

	_Initialize(UnicodeString::fromUTF8(pattern.String()));
#endif  // ~upstream
}


BStringFormat::~BStringFormat()
{
#ifndef HoG_GENODE
	delete fFormatter;
#endif  // ~not-HoG_GENODE
}


status_t
BStringFormat::InitCheck()
{
	return fInitStatus;
}


status_t
BStringFormat::Format(BString& output, const int64 arg) const
{
	if (fInitStatus != B_OK)
		return fInitStatus;

#ifndef HoG_GENODE
	UnicodeString buffer;
	UErrorCode error = U_ZERO_ERROR;

	Formattable arguments[] = {
		(int64)arg
	};

	FieldPosition pos;
	buffer = fFormatter->format(arguments, 1, buffer, pos, error);
	if (!U_SUCCESS(error))
		return B_ERROR;

	BStringByteSink byteSink(&output);
	buffer.toUTF8(byteSink);

#else  // HoG_GENODE:

	// Parse singular/plural words from pattern (for Tracker to display "100 items" etc)
	
	// note: optim: could Optim ctor by pre-calculating and keeping the end-result "BStringList words" instead of keeping the raw formatPattern
	// note: n/i stuff: we do expedient (not proper) tokenizing, make it work barely well enough for Tracker,
	// which only ever defines <case_one> and <case_other> (as fall back for all 3 other cases).
	
	BString case_0;
	BString case_plural;
	BString case_one;
	BString case_other;
	{
		BStringList tokens;
		{
			// hackish split of e.g.
			// - "{0, plural, one{# item} other{# items}}"
			// - "{0, plural, one{for # file} other{for # files}}"));
			// - ..etc
			formatPattern.Split( "{", true, tokens );
		}
		
		// n/i -- leave <case_0> empty
		// n/i -- leave <case_plural> empty
		tokens.Remove( 0 );
		
		// retrieve <case_one>
		{
			BStringList temp;
			tokens
				.StringAt( 0 )  // split/truncate e.g. "} other{"
					.Split( "}", true, temp );
			case_one = temp.First();
			//puts(case_one);  // e.g. "# item"
		}
		
		// retrieve <case_other>
		{
			BStringList temp;
			tokens
				.StringAt( 1 )
					.Split( "}", true, temp );
			case_other = temp.First();
			//puts(case_other);  // e.g. "# items"
		}
	}
	
	BString selected_case;
	{
		switch( arg )
		{
			case 0:  selected_case = case_0.Length()      ? case_0      : case_other;  break;
			case 1:  selected_case = case_one.Length()    ? case_one    : case_other;  break;
			default: selected_case = case_plural.Length() ? case_plural : case_other;  break;
		}
		
		BString val; val << arg;
		selected_case.ReplaceFirst( "#", val );
	}
	output = selected_case;
	//puts(output);  // e.g. "1 item"
#endif  // ~HoG_GENODE

	return B_OK;
}


#ifndef HoG_GENODE
status_t
BStringFormat::_Initialize(const UnicodeString& pattern)
{
	fInitStatus = B_OK;
	UErrorCode error = U_ZERO_ERROR;
	Locale* icuLocale
		= BLanguage::Private(&fLanguage).ICULocale();

	fFormatter = new MessageFormat(pattern, *icuLocale, error);

	if (fFormatter == NULL)
		fInitStatus = B_NO_MEMORY;

	if (!U_SUCCESS(error)) {
		delete fFormatter;
		fInitStatus = B_ERROR;
		fFormatter = NULL;
	}

	return fInitStatus;
}
#endif  // ~HoG_GENODE
