package com.vip.sdk.utils_lib.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Process;

/**
 * Author: rongjinsong(jason01.rong@vipshop.com)
 * Date: 2015-04-10
 * Time: 18:17
 * FIXME
 */
public abstract class WorkTask<Params, Progress, Result> {


    private ComparableFutureTask<Result> mFuture;
    private WorkerRunnable<Params, Result> mWorker;
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    private int mPriority = Process.THREAD_PRIORITY_BACKGROUND;

    public WorkTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(mPriority);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                return postResult(result);
            }
        };
        mFuture = new ComparableFutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
//                    FWLog.error(e.getMessage());
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }

        };
    }


    private Result postResult(final Result result) {
        ThreadPoolUtil.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                finish(result);
            }
        });
        return result;
    }


    protected abstract void onPreExecute();

    protected abstract Result doInBackground(Params... params);

    protected void onPostExecute(Result result) {
    }

    protected void onProgressUpdate(Progress... params) {
    }

    protected final void publishProgress(final Progress... values) {
        if (!isCancelled()) {
            ThreadPoolUtil.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    onProgressUpdate(values);
                }
            });
        }
    }

    public void execute(Params... params) {
        mWorker.mParams = params;
        onPreExecute();
        ThreadPoolUtil.execute(new ProvityRunnable(){
            public void job() {
                mFuture.run();
            }
        });
    }

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }


    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled();
        } else {
            onPostExecute(result);
        }
    }

    public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

    protected void onCancelled() {
    }

    public final boolean isCancelled() {
        return mCancelled.get();
    }


    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

}
