package org.redislabs.rnredis;

import android.os.AsyncTask;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;


abstract class ReactTask extends AsyncTask<Object, Void, WritableMap> {

    private String TAG = "ReactTask";

    private Callback     _callback;
    private ReactContext _context;

    ReactTask(ReactContext context, Callback callback) {
        _callback = callback;
        _context  = context;
    }

    @Override
    protected WritableMap doInBackground(Object... params) {
        return this.start();
    }

    abstract Object run()  throws Exception;
    abstract void finish();

    WritableMap start() {
        WritableMap jsResult;
        try {
            Object result = this.run();
            jsResult = this._returnJSResult(result);
        } catch (Exception e) {
            String      message = e.getMessage();
            WritableMap details = Arguments.createMap();

            if (e instanceof ReactException) {
                ReactException re = (ReactException)e;
                details = re.getDetails();
            }

            Log.d(TAG, message);
            jsResult = this._raiseJSException("ERNINT", message, details);
        } finally {
            if (!isCancelled()) {
                finish();
            }
        }

        return jsResult;
    }

    @Override
    protected void onPostExecute(final WritableMap result) {
        if (!_context.getCatalystInstance().isDestroyed()) {
            _callback.invoke(result);
        }
    }

    @Override
    protected void onCancelled() {
        if (!_context.getCatalystInstance().isDestroyed()) {
            _callback.invoke();
        }
    }

    ReactTask startAsync() {
        this.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        return this;
    }

    WritableMap _successResult(Boolean success) {
        WritableMap successMap = Arguments.createMap();
        successMap.putBoolean("success", success);
        return successMap;
    }

    WritableMap _raiseJSException(String code, String message) {
        return  _raiseJSException(code, message, null);
    }

    WritableMap _raiseJSException(String code, String message, WritableMap details) {
        if (details == null) {
            details = Arguments.createMap();
        }

        WritableMap errorMap = Arguments.createMap();

        errorMap.putString("code",    code);
        errorMap.putString("message", message);
        errorMap.putMap("details",    details);

        WritableMap resultMap = Arguments.createMap();
        resultMap.putMap("error", errorMap);

        return resultMap;
    }

    WritableMap _returnJSResult(Object result) {
        return ReactNativeUtils.writableMapFromObject("result", result);
    }
}

@@ -1755,32 +1755,111 @@
 sDestroyed()) %7B%0A
+            WritableMap msg = this._raiseJSException(%22ERNINT%22, %22Interrupted%22);%0A
             _cal
@@ -1871,16 +1871,19 @@
 .invoke(
+msg
 );%0A     

throw Interrupted error on ReactTask canceled