package com.tevinjeffrey.rmp.scraper; import com.squareup.okhttp.Call; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import com.tevinjeffrey.rmp.client.module.ClientModule$$ModuleAdapter; import com.tevinjeffrey.rmp.common.Parameter; import com.tevinjeffrey.rmp.common.Professor; import com.tevinjeffrey.rmp.common.RMP; import com.tevinjeffrey.rmp.scraper.search.Decider; import com.tevinjeffrey.rmp.scraper.search.Listing; import com.tevinjeffrey.rmp.scraper.search.RatingParser; import com.tevinjeffrey.rmp.scraper.search.SearchParser; import java.io.IOException; import java.util.List; import javax.inject.Inject; import rx.Observable; import rx.Subscriber; import rx.functions.Func1; import rx.schedulers.Schedulers; import static com.tevinjeffrey.rmp.common.RMP.RMP_BASE_URL; public class RMPScraper { final static String TAG = RMPScraper.class.getSimpleName(); OkHttpClient client; @Inject public RMPScraper(OkHttpClient client) { this.client = client; } public Observable<Professor> findBestProfessor(final Parameter params) { Observable<? extends Professor> firstChoice = getProfessors(params); params.university = ""; Observable<? extends Professor> secondChoice = getProfessors(params); return Observable.concat(firstChoice, secondChoice) .takeFirst(new Func1<Professor, Boolean>() { @Override public Boolean call(Professor professor) { return true; } }); } public Observable<? extends Professor> getProfessors(final Parameter params) { return performSearch(createUrlFromParams(params)) .flatMap(new Func1<String, Observable<ScrapeProfessor>>() { @Override public Observable<ScrapeProfessor> call(String response) { return getProfessors(response); } }) .filter(new Func1<ScrapeProfessor, Boolean>() { @Override public Boolean call(ScrapeProfessor professor) { return professor != null; } }) .toList() .flatMap(new Func1<List<ScrapeProfessor>, Observable<ScrapeProfessor>>() { @Override public Observable<ScrapeProfessor> call(List<ScrapeProfessor> professors) { return Observable.from(Decider.determineProfessor(professors, params)); } }); } public String createUrlFromParams(Parameter params) { return RMP_BASE_URL + "/search.jsp?stateselect=nj&query=" + params.lastName + (params.university.toLowerCase().contains("rutgers") ? "+rutgers":""); } public Observable<String> performSearch(final String url) { return makeRequest(url, TAG) .flatMap(new Func1<String, Observable<String>>() { @Override public Observable<String> call(String initalSearch) { final int numberOfProfessors = SearchParser.getNumberOfProfessors(initalSearch); if (numberOfProfessors <= 20) { return Observable.just(initalSearch); } else if (numberOfProfessors > 20) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { if (!subscriber.isUnsubscribed()) { for (int i = 0; i <= numberOfProfessors; i += 20) { subscriber.onNext(url + "&offset=" + i); } subscriber.onCompleted(); } } }).flatMap(new Func1<String, Observable<? extends String>>() { @Override public Observable<? extends String> call(String url) { return makeRequest(url, TAG); } }); } else { return Observable.empty(); } } }); } public Observable<String> makeRequest(String url, String tag) { return makeGetCall(new Request.Builder() .tag(tag) .url(url) .build()) .flatMap(new Func1<Call, Observable<Response>>() { @Override public Observable<Response> call(Call call) { return executeGetCall(call); } }) .flatMap(new Func1<Response, Observable<String>>() { @Override public Observable<String> call(Response response) { return mapResponseToString(response); } }); } private Observable<ScrapeProfessor> getProfessors(String response) { return Observable.from(SearchParser.getSearchResults(response)) .filter(new Func1<Listing, Boolean>() { @Override public Boolean call(Listing listing) { return !listing.getUrl().contains("Add"); } }) .flatMap(new Func1<Listing, Observable<? extends ScrapeProfessor>>() { @Override public Observable<? extends ScrapeProfessor> call(final Listing listing) { return makeRequest(RMP_BASE_URL + listing.getUrl(), TAG) .flatMap(new Func1<String, Observable<ScrapeProfessor>>() { @Override public Observable<ScrapeProfessor> call(String s) { return Observable.just(RatingParser.findProfessor(listing, s)); } }) .subscribeOn(Schedulers.io()); } }); } private Observable<String> mapResponseToString(final Response response) { System.out.println(response.request().urlString()); return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { if (!subscriber.isUnsubscribed()) { try { subscriber.onNext(response.body().string()); subscriber.onCompleted(); } catch (IOException e) { subscriber.onError(e); } } } }); } private Observable<Call> makeGetCall(final com.squareup.okhttp.Request request) { return Observable.create(new Observable.OnSubscribe<Call>() { @Override public void call(Subscriber<? super Call> subscriber) { if (!subscriber.isUnsubscribed()) { subscriber.onNext(client.newCall(request)); subscriber.onCompleted(); } } }); } private Observable<Response> executeGetCall(final Call call) { return Observable.create(new Observable.OnSubscribe<Response>() { @Override public void call(Subscriber<? super Response> subscriber) { if (!subscriber.isUnsubscribed()) { try { subscriber.onNext(call.execute()); subscriber.onCompleted(); } catch (IOException e) { subscriber.onError(e); } } } }); } }