package br.com.nglauber.starwarsjavarx.model.api; import android.net.Uri; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import br.com.nglauber.starwarsjavarx.model.Character; import br.com.nglauber.starwarsjavarx.model.Movie; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; import rx.Observable; import rx.functions.Action1; import rx.functions.Func1; import rx.functions.Func2; public class StarWarsApi { StarWarsApiDef service; HashMap<String, Person> peopleCache = new HashMap<>(); public StarWarsApi() { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); httpClient.addInterceptor(logging); Gson gson = new GsonBuilder().setLenient().create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://swapi.co/api/") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .client(httpClient.build()) .build(); service = retrofit.create(StarWarsApiDef.class); } public Observable<Movie> loadMovies() { return service.listMovies() .flatMap(new Func1<FilmResult, Observable<Film>>() { @Override public Observable<Film> call(FilmResult filmResult) { return Observable.from(filmResult.results); } }) .map(new Func1<Film, Movie>() { @Override public Movie call(Film film) { return new Movie(film.title, film.episodeId, new ArrayList<Character>()); } }); } public Observable<Movie> loadMoviesFull() { return service.listMovies() .flatMap(new Func1<FilmResult, Observable<Film>>() { @Override public Observable<Film> call(FilmResult filmResult) { return Observable.from(filmResult.results); } }) .flatMap(new Func1<Film, Observable<Movie>>() { @Override public Observable<Movie> call(Film film) { final Movie movieObj = new Movie(film.title, film.episodeId, new ArrayList<Character>()); return Observable.zip( Observable.just(movieObj), Observable.from(film.personUrls) .flatMap(new Func1<String, Observable<Person>>() { @Override public Observable<Person> call(final String personUrl) { return Observable.concat( getCache(personUrl), service.loadPerson(Uri.parse(personUrl).getLastPathSegment()).doOnNext(new Action1<Person>() { @Override public void call(Person person) { peopleCache.put(personUrl, person); } }) ).first(); } }) .map(new Func1<Person, Character>() { @Override public Character call(Person person) { return new Character(person.name, person.gender); } }) .toList(), new Func2<Movie, List<Character>, Movie>() { @Override public Movie call(Movie movie, List<Character> characters) { movie.characters.addAll(characters); return movie; } } ); } }); } private Observable<Person> getCache(final String personUrl) { return Observable.from(peopleCache.keySet()) .filter(new Func1<String, Boolean>() { @Override public Boolean call(String s) { return personUrl.equals(s); } }) .map(new Func1<String, Person>() { @Override public Person call(String s) { return peopleCache.get(s); } }); } }