package com.patloew.countries.ui.detail;
import android.content.Context;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableField;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import com.patloew.countries.R;
import com.patloew.countries.data.local.CountryRepo;
import com.patloew.countries.data.model.Country;
import com.patloew.countries.data.model.RealmString;
import com.patloew.countries.data.model.RealmStringMapEntry;
import com.patloew.countries.data.remote.CountryApi;
import com.patloew.countries.injection.qualifier.AppContext;
import com.patloew.countries.injection.scopes.PerActivity;
import com.patloew.countries.ui.BaseCountryViewModel;
import com.patloew.countries.ui.base.navigator.Navigator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import javax.inject.Inject;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
/* Copyright 2016 Patrick Löwenstein
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* FILE MODIFIED 2017 Tailored Media GmbH */
@PerActivity
public class DetailViewModel extends BaseCountryViewModel<DetailMvvm.View> implements DetailMvvm.ViewModel {
private static final String KEY_BORDERLIST = "borderList";
private final CountryApi countryApi;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
private final ObservableField<CharSequence> borders = new ObservableField<>();
private final ObservableField<CharSequence> currencies = new ObservableField<>();
private final ObservableField<CharSequence> languages = new ObservableField<>();
private final ObservableField<CharSequence> nameTranslations = new ObservableField<>();
private final ObservableBoolean loaded = new ObservableBoolean();
@Inject
public DetailViewModel(@AppContext Context context, CountryRepo countryRepo, CountryApi countryApi, Navigator navigator) {
super(context, countryRepo, navigator);
this.countryApi = countryApi;
}
@Override
public void saveInstanceState(@NonNull Bundle outState) {
outState.putCharSequence(KEY_BORDERLIST, borders.get());
}
@Override
public void restoreInstanceState(@NonNull Bundle savedInstanceState) {
if(savedInstanceState.containsKey(KEY_BORDERLIST)) {
borders.set(savedInstanceState.getCharSequence(KEY_BORDERLIST));
}
}
@Override
public void detachView() {
super.detachView();
compositeDisposable.clear();
}
@Override
public void update(Country country, boolean isLast) {
super.update(country, isLast);
compositeDisposable.clear();
loadBorders();
loadDataForField(nameTranslations, this::calculateNameTranslations);
loadDataForField(currencies, this::calculateCurrencies);
loadDataForField(languages, this::calculateLanguages);
}
private <T> void loadDataForField(ObservableField<T> field, Callable<T> producer) {
compositeDisposable.add(
Single.fromCallable(producer)
.subscribeOn(Schedulers.computation())
.subscribe(field::set, throwable -> {
Timber.e(throwable, "Could not load data for field");
field.set(null);
})
);
}
private CharSequence calculateLanguages() {
ArrayList<String> languageList = new ArrayList<>(country.languages.size());
for(RealmString language : country.languages) {
languageList.add(new Locale(language.value).getDisplayLanguage(DISPLAY_LOCALE));
}
Collections.sort(languageList);
return new SpannableStringBuilder(ctx.getText(R.string.country_languages)).append(TextUtils.join(", ", languageList));
}
private CharSequence calculateNameTranslations() {
ArrayList<String> nameList = new ArrayList<>(country.translations.size());
for(RealmStringMapEntry entry : country.translations) {
nameList.add(entry.value + " <i>(" + new Locale(entry.key).getDisplayLanguage(DISPLAY_LOCALE) + ")</i>");
}
Collections.sort(nameList);
return new SpannableStringBuilder(ctx.getText(R.string.country_name_translations)).append(Html.fromHtml(TextUtils.join(", ", nameList)));
}
private CharSequence calculateCurrencies() {
ArrayList<String> currenciesList = new ArrayList<>(country.currencies.size());
for (RealmString currencyRealmString : country.currencies) {
String currencyString = currencyRealmString.value;
if (Build.VERSION.SDK_INT >= 19) {
try {
Currency currency = Currency.getInstance(currencyString);
String currencySymbol = currency.getSymbol();
if (!currencyString.equals(currencySymbol)) {
currencySymbol = currencyString + ", " + currencySymbol;
}
currenciesList.add(currency.getDisplayName(DISPLAY_LOCALE) + " (" + currencySymbol + ")");
} catch (IllegalArgumentException ignore) {
currenciesList.add(currencyString);
}
} else {
currenciesList.add(currencyString);
}
}
Collections.sort(currenciesList);
return new SpannableStringBuilder(ctx.getText(R.string.country_currencies)).append(TextUtils.join(", ", currenciesList));
}
private void loadBorders() {
borders.set(null);
if(country.borders.size() > 0) {
compositeDisposable.add(
countryApi.getAllCountries()
.subscribe(this::calculateBorders, this::onLoadCountriesError)
);
} else {
loaded.set(true);
}
}
private void calculateBorders(List<Country> countryList) {
if(countryList != null) {
List<String> borderList = new ArrayList<>(country.borders.size());
ArrayList<String> alpha3List = new ArrayList<>(country.borders.size());
for (RealmString borderAlpha3CodeString : country.borders) {
alpha3List.add(borderAlpha3CodeString.value);
}
for (Country c : countryList) {
if (alpha3List.contains(c.alpha3Code)) {
borderList.add(c.name);
alpha3List.remove(c.alpha3Code);
if (alpha3List.isEmpty()) {
break;
}
}
}
borders.set(new SpannableStringBuilder(ctx.getText(R.string.country_borders)).append(TextUtils.join(", ", borderList)));
}
loaded.set(true);
}
private void onLoadCountriesError(Throwable throwable) {
Timber.e(throwable, "Could not load countries");
loaded.set(true);
}
// Properties
@Override
public ObservableField<CharSequence> getNameTranslations() {
return nameTranslations;
}
@Override
public ObservableField<CharSequence> getLanguages() {
return languages;
}
@Override
public ObservableBoolean isLoaded() {
return loaded;
}
@Override
public ObservableField<CharSequence> getBorders() {
return borders;
}
@Override
public ObservableField<CharSequence> getCurrencies() {
return currencies;
}
}