package com.circlegate.liban.task;
import android.os.Bundle;
import com.circlegate.liban.base.ApiBase.IApiParcelable;
import com.circlegate.liban.base.CustomCollections.LRUCache;
import com.circlegate.liban.task.TaskErrors.BaseError;
import com.circlegate.liban.task.TaskErrors.ITaskError;
import com.circlegate.liban.task.TaskErrors.TaskException;
import com.circlegate.liban.task.TaskInterfaces.ITask;
import com.circlegate.liban.task.TaskInterfaces.ITaskContext;
import com.circlegate.liban.task.TaskInterfaces.ITaskParam;
import com.circlegate.liban.task.TaskInterfaces.ITaskProgressListener;
import com.circlegate.liban.task.TaskInterfaces.ITaskResult;
import com.circlegate.liban.task.TaskInterfaces.ITaskResultListener;
import com.circlegate.liban.utils.EqualsUtils;
import com.circlegate.liban.utils.LogUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Queue;
public class TaskCommon {
public static class TaskSimple implements ITask, ITaskResultListener {
private final ITaskParam param;
private final Bundle bundle;
private HashMap<String, Object> processObjects; // lazy loaded
public TaskSimple(ITaskParam param, Bundle bundle) {
this.param = param;
this.bundle = bundle;
}
public ITaskParam getParam() {
return this.param;
}
public Bundle getBundle() {
return this.bundle;
}
@Override
public Object putProcessObj(String key, Object obj) {
if (processObjects == null)
processObjects = new HashMap<>();
return processObjects.put(key, obj);
}
@Override
public <T> T getProcessObj(String key) {
if (processObjects == null)
return null;
else
return (T)processObjects.get(key);
}
@Override
public String getId() {
return "NO_ID";
}
@Override
public boolean isCanceled() {
return false;
}
@Override
public int getSkipCount() {
return 0;
}
@Override
public int getProgress() {
return ITaskProgressListener.INDETERMINATE_PROGRESS;
}
@Override
public String getProgressState() {
return null;
}
@Override
public ITaskResultListener getListener() {
return this;
}
@Override
public boolean canCacheReferenceToParamResult() {
return false;
}
@Override
public void onTaskCompleted(String id, ITaskResult result, Bundle bundle) {
}
@Override
public void onTaskProgress(int progress, String progressState) {
}
}
public static class TaskCache {
private final LRUCache<ITaskParam, ITaskResult> cache = new LRUCache<>(50);
private final Queue<IApiParcelable> historyParams = new LinkedList<>();
public Object getLock() {
return this;
}
public synchronized ITaskResult get(ITaskParam param) {
return cache.get(param);
}
public synchronized void putIfCan(ITask task, ITaskParam param, ITaskResult optResult) {
// Pozor ma moznost vzniku memory leaku, pokud by treba param obsahoval referenci na aktivity/fragment apod!
// Kazdy task explicitne musi mit urceno, jestli lze reference na Param/Result ukladat nebo ne...
if (task.canCacheReferenceToParamResult()) {
if (optResult != null && optResult.isCacheableResult()) {
cache.put(param, optResult);
}
if (param instanceof IApiParcelable) {
historyParams.add((IApiParcelable)param);
while (historyParams.size() > 50) {
historyParams.poll();
}
}
}
}
public synchronized void remove(ITaskParam param) {
cache.remove(param);
}
public synchronized void clear() {
cache.clear();
}
public synchronized List<Entry<ITaskParam, ITaskResult>> generateAll() {
return cache.generateAll();
}
public synchronized List<IApiParcelable> generateHistoryParams() {
return new ArrayList<>(historyParams);
}
}
public static abstract class TaskParam implements ITaskParam {
private static final String TAG = TaskParam.class.getSimpleName();
@Override
public boolean isExecutionInParallelForbidden(ITaskContext context) {
return false;
}
@Override
public ITaskResult createResult(ITaskContext context, ITask task) {
TaskCache cache = context.getTaskCache();
ITaskResult result = cache.get(this);
if (result == null || !result.canUseCachedResultNow()) {
try {
result = createResultUncached(context, task);
}
catch (TaskException ex) {
result = createErrorResult(context, task, ex.getTaskError());
}
catch (Exception ex) {
LogUtils.e(getClass().getSimpleName(), "TaskParam.createResult: createResultUncached thrown an exception", ex);
result = createErrorResult(context, task, BaseError.ERR_UNKNOWN_ERROR);
}
}
else {
LogUtils.d(TAG, "Result taken from cache");
}
cache.putIfCan(task, this, result);
return result;
}
public abstract ITaskResult createResultUncached(ITaskContext context, ITask task) throws TaskException;
}
public static class TaskResultBase<TParam extends ITaskParam, TError extends ITaskError> implements ITaskResult {
private final TParam param;
private final TError error;
public TaskResultBase(TParam param, TError error) {
this.param = param;
this.error = error;
}
public TParam getParam() {
return this.param;
}
public TError getError() {
return this.error;
}
@Override
public final boolean isValidResult() {
return error.isOk();
}
@Override
public boolean isCacheableResult() {
return false; // defaultni hodnota je false
}
@Override
public boolean canUseCachedResultNow() {
return true;
}
}
public static class TaskResult<TParam extends ITaskParam> extends TaskResultBase<TParam, ITaskError> {
public TaskResult(TParam param, ITaskError error) {
super(param, error);
}
}
public static class BatchTaskParam extends TaskParam {
private final ImmutableList<ITaskParam> params; // abstract
public BatchTaskParam(ImmutableList<ITaskParam> params) {
this.params = params;
}
public ImmutableList<ITaskParam> getParams() {
return this.params;
}
private int _hash = EqualsUtils.HASHCODE_INVALID;
@Override
public int hashCode() {
if (_hash == EqualsUtils.HASHCODE_INVALID) {
int _hash = 17;
_hash = _hash * 29 + EqualsUtils.itemsHashCode(params);
this._hash = _hash == EqualsUtils.HASHCODE_INVALID ? EqualsUtils.HASHCODE_INVALID_REPLACEMENT : _hash;
}
return this._hash;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof BatchTaskParam)) {
return false;
}
BatchTaskParam lhs = (BatchTaskParam) o;
return lhs != null &&
EqualsUtils.itemsEqual(params, lhs.params);
}
@Override
public String getSerialExecutionKey(ITaskContext context) {
if (params.size() > 0) {
String ret = params.get(0).getSerialExecutionKey(context);
for (int i = 1; i < params.size(); i++) {
if (!EqualsUtils.equalsCheckNull(ret, params.get(i).getSerialExecutionKey(context))) {
throw new RuntimeException("getSerialExecutionKeys are different!");
}
}
return ret;
}
else
return DEFAULT_SERIAL_EXECUTION_KEY;
}
@Override
public boolean isExecutionInParallelForbidden(ITaskContext context) {
if (params.size() > 0) {
boolean ret = params.get(0).isExecutionInParallelForbidden(context);
for (int i = 1; i < params.size(); i++) {
if (ret != params.get(i).isExecutionInParallelForbidden(context)) {
throw new RuntimeException("isExecutionInParallelForbidden results are different!");
}
}
return ret;
}
else
return false;
}
@Override
public BatchTaskResult createResultUncached(ITaskContext context, ITask task) {
ImmutableList.Builder<ITaskResult> results = ImmutableList.builder();
for (ITaskParam p : params) {
results.add(p.createResult(context, task));
}
return new BatchTaskResult(this, BaseError.ERR_OK, results.build());
}
@Override
public BatchTaskResult createErrorResult(ITaskContext context, ITask task, ITaskError error) {
return new BatchTaskResult(this, error, null);
}
}
public static class BatchTaskResult extends TaskResult<BatchTaskParam> {
private final ImmutableList<ITaskResult> results; // abstract optional - pokud null -> error result
public BatchTaskResult(BatchTaskParam param, ITaskError error, ImmutableList<ITaskResult> results) {
super(param, error);
this.results = results;
}
public ImmutableList<ITaskResult> getResults() {
return this.results;
}
}
public static abstract class AsyncTaskParam extends TaskParam {
private final String serialExecutionKey;
public AsyncTaskParam(String serialExecutionKey) {
this.serialExecutionKey = serialExecutionKey;
}
@Override
public String getSerialExecutionKey(ITaskContext context) {
return serialExecutionKey;
}
@Override
public ITaskResult createErrorResult(ITaskContext context, ITask task, ITaskError error) {
return new TaskResult<>(this, error);
}
@Override
public ITaskResult createResultUncached(ITaskContext context, ITask task) throws TaskException {
execute(context, task);
return new TaskResult<>(this, BaseError.ERR_OK);
}
public abstract void execute(ITaskContext context, ITask task) throws TaskException;
}
public static class EmptyTaskListener implements ITaskResultListener, ITaskProgressListener {
@Override
public void onTaskProgress(String id, ITaskParam param, Bundle bundle, int progress, String progressState) {
}
@Override
public void onTaskCompleted(String id, ITaskResult result, Bundle bundle) {
}
}
}