/*******************************************************************************
* Copyleft 2013 Massimiliano Leone - massimiliano.leone@iubris.net .
*
* UIyssesSearchAsyncTask.java is part of 'Ulysses'.
******************************************************************************/
package net.iubris.ulysses.tasks.search.aware;
import java.util.concurrent.Executor;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.iubris.diane.aware.cache.exceptions.base.CacheEmptyException;
import net.iubris.diane.aware.cache.exceptions.base.CacheTooOldException;
import net.iubris.diane.aware.location.exceptions.base.LocationFreshNullException;
import net.iubris.diane.aware.network.exceptions.base.NoNetworkException;
import net.iubris.diane.searcher.aware.cache.exceptions.CacheAwareSearchException;
import net.iubris.diane.searcher.aware.exceptions.base.StillSearchException;
import net.iubris.diane.searcher.aware.full.exception.NoNetworkAndCacheEmptyException;
import net.iubris.diane.searcher.aware.location.exceptions.LocationAwareSearchException;
import net.iubris.diane.searcher.aware.location.exceptions.base.LocationNotSoUsefulException;
import net.iubris.diane.searcher.aware.location.exceptions.base.LocationTooNearException;
import net.iubris.diane.searcher.aware.network.exceptions.NetworkAwareSearchException;
import net.iubris.diane.tasks.search.RoboSearchAwareAsyncTask;
import net.iubris.ulysses.engine.searcher.aware.full.DefaultUlyssesSearcher;
import net.iubris.ulysses.engine.searcher.aware.full.UlyssesSearcher;
import net.iubris.ulysses.engine.searcher.location.aware.full.UlyssesLocalizedSearcher;
import net.iubris.ulysses.engine.searcher.location.aware.network.exceptions.google.PlacesRetrievingException;
import net.iubris.ulysses.engine.searcher.location.aware.network.exceptions.google.PlacesTyrannusStatusException;
import net.iubris.ulysses.engine.searcher.location.aware.network.exceptions.google.PlacesUnbelievableZeroResultStatusException;
import net.iubris.ulysses.model.Place;
import net.iubris.ulysses.tasks.search.aware.exceptions.ZeroResultException;
import net.iubris.ulysses.tasks.search.aware.locationstate.LocationExceptionState;
import net.iubris.ulysses.tasks.search.aware.locationstate.provider.MetaProviderForLocationExceptionStateForLocationNotSoUsefulException;
import net.iubris.ulysses.tasks.search.aware.locationstate.provider.MetaProviderForLocationExceptionStateForLocationTooNearException;
import roboguice.util.Ln;
import android.content.Context;
import android.location.Location;
import android.os.Handler;
@Singleton
public class SearchAwareTask extends RoboSearchAwareAsyncTask<DefaultUlyssesSearcher,Void,Void,List<Place>> implements SearchAwareTaskLocationStateable {
@Inject
protected UlyssesSearcher ulyssesSearcher;
@Inject
protected UlyssesLocalizedSearcher ulyssesLocalizedSearcher;
@Inject
protected MetaProviderForLocationExceptionStateForLocationNotSoUsefulException metaProviderForLocationExceptionStateForLocationNotSoUsefulException;
@Inject
protected MetaProviderForLocationExceptionStateForLocationTooNearException metaProviderForLocationExceptionStateForLocationTooNearException;
private List<Place> result;
private boolean foundByNetwork;
private boolean foundByCache;
protected SearchAwareTask(Context context, Executor executor) {
super(context, executor);
}
protected SearchAwareTask(Context context, Handler handler, Executor executor) {
super(context, handler, executor);
}
protected SearchAwareTask(Context context, Handler handler) {
super(context, handler);
}
@Inject
public SearchAwareTask(Context context) {
super(context);
}
/**
* calls {@link DefaultUlyssesSearcher#search()}
* @throws NetworkAwareSearchException
* @throws StillSearchException
* @throws PlacesTyrannusStatusException
* @throws PlacesUnbelievableZeroResultStatusException
* @throws PlacesRetrievingException
* @throws NoNetworkException
* @throws LocationNotSoUsefulException
* @throws LocationTooNearException
* @throws ZeroResultException
* @throws
*/
@Override
public List<Place> call() throws LocationFreshNullException, LocationTooNearException, LocationNotSoUsefulException,
NoNetworkException, CacheTooOldException, CacheEmptyException, CacheAwareSearchException, NoNetworkAndCacheEmptyException,
PlacesRetrievingException, PlacesUnbelievableZeroResultStatusException, PlacesTyrannusStatusException,
StillSearchException, ZeroResultException {
ulyssesSearcher.search();
result = ulyssesSearcher.getResult();
if (result.size() == 0) {
throw new ZeroResultException();
}
return result;
}
@SuppressWarnings("deprecation")
@Override
protected void onSuccess(List<Place> result) throws Exception {
super.onSuccess(result);
doOnSuccess(result);
}
/**
* try to get any result using cache result
*/
@Override
protected void onException(NoNetworkException e) throws RuntimeException {
eventuallyHandleInUIPreSearchingByCacheInOnNoNetworkException(); // 1
foundByNetwork = false;
List<Place> result = ulyssesSearcher.getResult();
int size = result.size();
Ln.d("results: "+result.size());
if (size==0) {
Throwable cause = e.getCause();
// if NoNetworkException && CacheEmpty
if (cause instanceof CacheEmptyException) {
onException((CacheEmptyException)cause);
} else {
return;
}
} else { // results!
// since we have some result, we change LocationExceptionStateS to default implementations
// setLocationExceptionStatesDefault();
doOnSuccess(result);
if (ulyssesSearcher.isFoundByCache()) {
eventuallyHandleInUISearchingFoundByCacheInOnNoNetworkException(); // 2
} else { // here reached when results from last search (in-memory)
eventuallyHandleInUISearchingFoundByNetworkUsingInMemoryResultsInOnNoNetworkException(); // 3
}
}
}
protected void eventuallyHandleInUIPreSearchingByCacheInOnNoNetworkException() {} // 1
protected void eventuallyHandleInUISearchingFoundByCacheInOnNoNetworkException() {} // 2
// protected void eventuallyHandleInUISearchingFailedByCacheInOnNoNetworkException() {}
// protected void eventuallyHandleInUIAnyExceptionSearchingByCacheInOnNoNetworkException(Exception e) {}
protected void eventuallyHandleInUISearchingFoundByNetworkUsingInMemoryResultsInOnNoNetworkException() {} // 3
// LocationTooNear - start
@Override
protected void onException(LocationTooNearException e) {
super.onException(e);
Ln.d("onException[LocationTooNearException]: "+e.getMessage());
final Location location = ulyssesSearcher.getLocation();
Ln.d("onException[LocationTooNearException]: using location: "+location);
try {
metaProviderForLocationExceptionStateForLocationTooNearException
.eventuallyInit(this).get()
.tryToSearch( ulyssesSearcher.getLocation() );
} catch (NoNetworkException e1) {
onException(e1);
} catch (NetworkAwareSearchException e2) {
onException(e2);
}
}
// protected void eventuallyHandleInUIPreSearchingOnLocationTooNearExceptionWhenNeverHappenedBefore() {} // 1
// protected void eventuallyHandleInUISearchingFailedByCacheInLocationTooNearException(CacheSearchExceptions cacheSearchExceptions) {}; // 2
// protected void eventuallyHandleInUISearchingFailedByCacheInLocationTooNearException() {}; // 2
// protected void eventuallyHandleInUISearchingFailedByCacheInLocationTooNearExceptionWithoutSpecificReason() {} // 3
// protected void eventuallyHandleInUISearchResultUsingCacheOnLocationTooNearExceptionIfNeverResultBefore(List<Place> resultForced) {} // 4
// protected void eventuallyHandleInUISearchResultUsingNetworkOnLocationTooNearExceptionIfNeverResultBefore(List<Place> resultForced) {} // 5
// protected void eventuallyShowErrorMessageOnLocationTooNearException(LocationTooNearException e) {}
// protected void eventuallyShowErrorMessageOnLocationTooNearException() {} // 6
// LocationTooNear - end
// LocationNotSoUseful - start
@Override
protected void onException(LocationNotSoUsefulException e) {
super.onException(e);
Ln.d("onException[LocationNotSoUsefulException]: "+e.getMessage());
final Location location = ulyssesSearcher.getLocation();
Ln.d("onException[LocationNotSoUsefulException]: using location: "+location);
try {
metaProviderForLocationExceptionStateForLocationNotSoUsefulException
.eventuallyInit(this).get()
.tryToSearch( ulyssesSearcher.getLocation() );
} catch (NoNetworkException e1) {
onException(e);
} catch (NetworkAwareSearchException e1) {
onException(e);
}
}
// protected void eventuallyHandleInUIPreSearchingOnLocationNotSoUsefulExceptionWhenNeverHappenedBefore() {}
// protected void eventuallyHandleInUISearchingFailedByCacheInNotSoUsefulException(CacheSearchExceptions cacheSearchExceptions) {};
// protected void eventuallyHandleInUISearchingFailedByCacheInNotSoUsefulExceptionWithoutSpecificReason() {}
// protected void eventuallyHandleInUISearchResultUsingNetworkOnNotSoUsefulExceptionIfNeverResultBefore(List<Place> resultForced) {}
// protected void eventuallyHandleInUISearchResultUsingCacheOnNotSoUsefulExceptionIfNeverResultBefore(List<Place> resultForced) {}
// protected void eventuallyShowErrorMessageOnLocationNotSoUsefulException(LocationNotSoUsefulException e) {}
// protected void eventuallyShowErrorMessageOnLocationNotSoUsefulException() {}
// LocationNotSoUseful - end
@Override
public UlyssesSearcher getSearcher() {
return ulyssesSearcher;
}
@Override
public UlyssesLocalizedSearcher getLocalizedSearcher() {
return ulyssesLocalizedSearcher;
}
@Override
public void doOnSuccess(List<Place> result) throws RuntimeException {
setLocationExceptionStatesAfterFirstResult();
if (ulyssesSearcher.isFoundByCache()) {
setResultFoundByCache();
} else {
setResultFoundByNetwork();
}
}
@Override
public void setLocationExceptionState(LocationExceptionState currentLocationExceptionState, LocationExceptionState futureLocationExceptionState) {
LocationExceptionState locationExceptionStateToBeCompletedExecution = currentLocationExceptionState;
setLocationExceptionState(futureLocationExceptionState, futureLocationExceptionState.getHandlingLocationAwareSearchExceptionClass() );
locationExceptionStateToBeCompletedExecution.completeExecution();
}
private void setLocationExceptionState(LocationExceptionState futureLocationExceptionState, Class<? extends LocationAwareSearchException> extendingLocationAwareSearchExceptionClass) {
try {
LocationStateExceptionClassHandler.valueOf(extendingLocationAwareSearchExceptionClass.getClass().getSimpleName()).setLocationExceptionState(futureLocationExceptionState, this);
} catch (IllegalArgumentException e) {
Ln.d("no LocationStateExceptionClassHandler instance for: "+extendingLocationAwareSearchExceptionClass);
}
}
private enum LocationStateExceptionClassHandler {
LocationTooNearException {
@Override
public void setLocationExceptionState(LocationExceptionState futureLocationExceptionState, SearchAwareTask searchAwareTask) {
searchAwareTask.metaProviderForLocationExceptionStateForLocationTooNearException.setLocationExceptionState(futureLocationExceptionState);
}
},
LocationNotSoUsefulException {
@Override
public void setLocationExceptionState(LocationExceptionState futureLocationExceptionState, SearchAwareTask searchAwareTask) {
searchAwareTask.metaProviderForLocationExceptionStateForLocationNotSoUsefulException.setLocationExceptionState(futureLocationExceptionState);
}
};
abstract public void setLocationExceptionState(LocationExceptionState futureLocationExceptionState, SearchAwareTask searchAwareTask);
}
private void setLocationExceptionStatesAfterFirstResult() {
this.metaProviderForLocationExceptionStateForLocationTooNearException.setAfterFirstResult();
this.metaProviderForLocationExceptionStateForLocationNotSoUsefulException.setAfterFirstResult();
}
@Override
public void setResultFoundByNetwork() {
foundByNetwork = true;
foundByCache = false;
}
@Override
public void setResultFoundByCache() {
foundByNetwork = false;
foundByCache = true;
}
protected void onException(ZeroResultException arg0) throws RuntimeException {}
protected void onException(CacheEmptyException e) throws RuntimeException {}
public List<Place> getResult() {
return result;
}
public boolean isFoundByCache() {
return foundByCache;
}
public boolean isFoundByNetwork() {
return foundByNetwork;
}
}