public static abstract class ApiCreator<T> implements Parcelable.Creator<T> {
    @Override
    public final T createFromParcel(Parcel source) {
        ApiParcelInputWrp wrp = new ApiParcelInputWrp(source);
        return create(wrp);
    }

    public abstract T create(ApiDataInput d);
} public static abstract class ApiParcelable extends ApiObject implements IApiParcelable {
    public int describeContents() {
        return 0;
    }

    public final void writeToParcel(Parcel dest, int flags) {
        baseWriteToParcel(this, dest, flags);
    }


    public static int baseDescribeContents() {
        return 0;
    }

    public static void baseWriteToParcel(IApiParcelable parcelable, Parcel dest, int flags) {
        ApiParcelOutputWrp p = new ApiParcelOutputWrp(dest);
        parcelable.save(p, flags);
    }
} public interface IApiParcelable extends IApiObject, Parcelable {
    // tridy implementujici toto rozhrani musi mit clen public static ApiCreator CREATOR;
} public interface ApiDataInput extends ApiDataInputOutputBase {
    int getDataAppVersionCode(); // version code verze aplikace, ktera puvodne dana data ulozila...

    boolean readBoolean();
    int readInt();
    long readLong();

    byte[] readBytes();
    String readString();
    Bitmap readBitmap();
    <T extends IApiObject> T readObject(ApiCreator<T> creator);
    <T extends IApiParcelable> T readParcelableWithName();
    <T extends IApiObject> ImmutableList<T> readImmutableList(ApiCreator<T> creator);
    <T extends IApiParcelable> ImmutableList<T> readImmutableListWithNames();

    <T extends IApiParcelable> T readOptParcelableWithName();
} public interface ApiDataOutput extends ApiDataInputOutputBase {
    boolean write(boolean value);
    void write(int value);
    void write(long value);

    void write(byte[] value);
    void write(String value);
    void write(Bitmap value, int flags);
    void write(IApiObject value, int flags);
    void writeWithName(IApiParcelable value, int flags);
    void write(Collection<? extends IApiObject> value, int flags);
    void writeOpt(IApiObject value, int flags);
    void writeOptWithName(IApiParcelable value, int flags);
} 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 TaskResult<TParam extends ITaskParam> extends TaskResultBase<TParam, ITaskError> {
    public TaskResult(TParam param, ITaskError error) {
        super(param, error);
    }
} public static class BaseError extends TaskError {
    public static final int OK = 0;
    public static final int UNKNOWN_ERROR = -1;
    public static final int SERVER_ERROR = -2;
    public static final int CONNECTION_ERROR_COMMUNICATION = -3;
    public static final int CONNECTION_ERROR_UNEXPECTED_RES = -4;
    public static final int FILE_ERROR = -5;
    public static final int LOGIN_ERROR = -6;

    public static final BaseError ERR_OK = new BaseError(OK, 0) {
        @Override
        public boolean isOk() {
            return true;
        }
    };
    public static final BaseError ERR_UNKNOWN_ERROR = new BaseError(UNKNOWN_ERROR, R.string.err_unknown_error);
    public static final BaseError ERR_SERVER_ERROR = new BaseError(SERVER_ERROR, R.string.err_server_error);
    public static final BaseError ERR_CONNECTION_ERROR_COMMUNICATION = new BaseError(CONNECTION_ERROR_COMMUNICATION, R.string.err_connection_error_communication);
    public static final BaseError ERR_CONNECTION_ERROR_UNEXPECTED_RES = new BaseError(CONNECTION_ERROR_UNEXPECTED_RES, R.string.err_connection_error_unexpected_res);
    public static final BaseError ERR_FILE_ERROR = new BaseError(FILE_ERROR, R.string.err_file_error);
    public static final BaseError ERR_LOGIN_ERROR = new BaseError(LOGIN_ERROR, R.string.err_login_error);
    // nezapomenout pridavat case vetve v ApiCreatoru!

    private final int id;
    private final int resId;

    private BaseError(int id, int resId) {
        this.id = id;
        this.resId = resId;
    }

    @Override
    public void save(ApiDataOutput d, int flags) {
        d.write(this.id);
    }

    public int getId() {
        return this.id;
    }

    public int getResId() {
        return this.resId;
    }

    @Override
    public int hashCode() {
        int _hash = 17;
        _hash = _hash * 29 + id;
        //_hash = _hash * 29 + resId;
        return _hash;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof BaseError)) {
            return false;
        }

        BaseError lhs = (BaseError) o;
        return lhs != null &&
                id == lhs.id;
        //resId == lhs.resId;
    }


    @Override
    public CharSequence getMsg(ITaskContext context) {
        return resId != 0 ? context.getAndroidContext().getString(resId) : "";
    }

    @Override
    public String getGoogleAnalyticsId() {
        return "BaseError:" + id;
    }

    public static boolean isConnectionError(ITaskError error) {
        return error instanceof BaseError
                && (((BaseError)error).id == CONNECTION_ERROR_COMMUNICATION || ((BaseError)error).id == CONNECTION_ERROR_UNEXPECTED_RES);
    }

    public static final ApiCreator<BaseError> CREATOR = new ApiCreator<BaseError>() {
        public BaseError create(ApiDataInput d) {
            int id = d.readInt();
            switch (id) {
                case OK: return ERR_OK;
                case UNKNOWN_ERROR: return ERR_UNKNOWN_ERROR;
                case SERVER_ERROR: return ERR_SERVER_ERROR;
                case CONNECTION_ERROR_COMMUNICATION: return ERR_CONNECTION_ERROR_COMMUNICATION;
                case CONNECTION_ERROR_UNEXPECTED_RES: return ERR_CONNECTION_ERROR_UNEXPECTED_RES;
                case FILE_ERROR: return ERR_FILE_ERROR;
                case LOGIN_ERROR: return ERR_LOGIN_ERROR;
                default: throw new NotImplementedException();
            }
        }

        public BaseError[] newArray(int size) { return new BaseError[size]; }
    };
} public interface ITaskError extends IApiParcelable {
    boolean isOk();
    CharSequence getMsg(ITaskContext context);
    //DialogFragment createDialog(ITaskContext context, boolean finish);
    void showToast(ITaskContext context);
    TaskException createExc(ITaskContext context);
    String getGoogleAnalyticsId();
}     public static abstract class TaskError extends ApiParcelable implements ITaskError {
        @Override
        public boolean isOk() {
            return false;
        }

//        @Override
//        public DialogFragment createDialog(ITaskContext context, boolean finish) {
//            return TaskErrorDialog.newInstance(getDialogMsg(context), finish);
//        }

        @Override
        public void showToast(ITaskContext context) {
            LogUtils.e("TaskError", "showToast: " + getMsg(context).toString());
            Toast.makeText(context.getAndroidContext(), getMsg(context), Toast.LENGTH_SHORT).show();
        }

        @Override
        public TaskException createExc(ITaskContext context) {
            return new TaskException(this);
        }

        //protected CharSequence getDialogMsg(ITaskContext context) {
        //    return getMsg(context);
        //}

        //protected CharSequence getToastMsg(ITaskContext context) {
        //    return getMsg(context);
        //}
    } public static class TaskException extends Exception {
    private final ITaskError taskError;

    public TaskException(ITaskError taskError) {
        this.taskError = taskError;
    }

    public ITaskError getTaskError() {
        return taskError;
    }
} public interface ITask  {
    public static String PROCESS_BUNDLE_FILE_SIZE = "PROCESS_BUNDLE_FILE_SIZE"; // Pouzito pri stahovani...

    String getId();
    ITaskParam getParam();
    Bundle getBundle();
    Object putProcessObj(String key, Object obj); // vraci pripadne puvodni hodnotu
    <T> T getProcessObj(String key);
    boolean isCanceled();
    int getSkipCount();
    int getProgress();
    String getProgressState();
    ITaskResultListener getListener();
    boolean canCacheReferenceToParamResult(); // povolit jenom v pripade, kdy nemuze dochazek k memory leakum! (reference na aktivity/fragmenty)
    void onTaskProgress(int progress, String progressState);
} public interface ITaskContext extends IGlobalContext {
    ITaskExecutor getTaskExecutor();
    TaskCache getTaskCache();
    String getCurrentLangAbbrev();
    String getCurrentCountryAbbrev();
}     public interface ITaskParam {
        static String DEFAULT_SERIAL_EXECUTION_KEY = "";

//	    static int TASK_CLASS_ID_CPP = 1;
//	    static int TASK_CLASS_ID_WS_GOOGLE = 2;
//	    static int TASK_CLASS_ID_WS_CIRCLEGATE = 3;
//	    static int TASK_CLASS_ID_WS_CIRCLEGATE_DWN = 4;
//	    static int TASK_CLASS_ID_GOOGLE_BILLING = 5;
//        static int TASK_CLASS_ID_CD_IPWS = 6;
//        static int TASK_CLASS_ID_CD_CMN = 7;

        String getSerialExecutionKey(ITaskContext context);
        boolean isExecutionInParallelForbidden(ITaskContext context);
        ITaskResult createResult(ITaskContext context, ITask task);
        ITaskResult createErrorResult(ITaskContext context, ITask task, ITaskError error);
    } public interface ITaskResult {
    ITaskParam getParam();
    boolean isValidResult();
    boolean isCacheableResult();
    boolean canUseCachedResultNow();
    ITaskError getError();
} public class TrezorException extends RuntimeException {
    public static final int TYPE_NOT_CONNECTED = 0;
    public static final int TYPE_NEEDS_PERMISSION = 1;
    public static final int TYPE_COMMUNICATION_ERROR = 2;
    public static final int TYPE_UNEXPECTED_RESPONSE = 3;
    // pozor - pri pridavani nezapominat pridavat prislusne polozky v app: TrezorTasks.TrezorError

    private final int type;

    public TrezorException(int type) {
        this.type = type;
    }

    public TrezorException(int type, Throwable throwable) {
        super(throwable);
        this.type = type;
    }

    public int getType() {
        return this.type;
    }
} public class TrezorManager {
    private static final String TAG = TrezorManager.class.getSimpleName();

    private final Context context;
    private final UsbManager usbManager;

    private UsbDevice deviceWithoutPermission;
    private TrezorDevice device; // lazy loaded

    public TrezorManager(Context context) {
        this.context = context.getApplicationContext();
        this.usbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
    }


    public synchronized boolean tryConnectDevice() {
        return tryGetDevice() != null;
    }

    public synchronized void closeDeviceConnection() {
        if (device != null) {
            Timber.d(TAG, "closeDeviceConnection: closing");
            device.close();
            device = null;
        }
        else
            Timber.d(TAG, "closeDeviceConnection: no device connected now");
    }

    public synchronized boolean hasDeviceWithoutPermission(boolean refreshDevices) {
        if (refreshDevices)
            tryGetDevice();
        return this.device == null && this.deviceWithoutPermission != null;
    }

    public synchronized void requestDevicePermissionIfCan(boolean refreshDevices) {
        if (hasDeviceWithoutPermission(refreshDevices)) {
            usbManager.requestPermission(deviceWithoutPermission, PendingIntent.getBroadcast(context, 0, new Intent(UsbPermissionReceiver.ACTION), 0));
        }
    }

    public synchronized Message sendMessage(Message message) throws TrezorException {
        TrezorDevice device = tryGetDevice();
        if (device == null)
            throw new TrezorException(deviceWithoutPermission != null ? TrezorException.TYPE_NEEDS_PERMISSION : TrezorException.TYPE_NOT_CONNECTED);
        else {
            try {
                return device.sendMessage(message);
            }
            catch (Exception e) {
                Timber.e(TAG, "sendMessage: device.sendMessage thrown exception:", e);
                throw new TrezorException(TrezorException.TYPE_COMMUNICATION_ERROR, e);
            }
        }
    }


    public static Message parseMessageFromBytes(MessageType type, byte[] data) throws InvalidProtocolBufferException {
        try {
            String className = com.satoshilabs.trezor.lib.protobuf.TrezorMessage.class.getName() + "$" + type.name().replace("MessageType_", "");
            Class cls = Class.forName(className);
            Method method = cls.getDeclaredMethod("parseFrom", byte[].class);
            //noinspection PrimitiveArrayArgumentToVariableArgMethod
            return (Message)method.invoke(null, data); // TODO cache methods for faster start?
        }
        catch (Exception ex) {
            throw new InvalidProtocolBufferException("Exception while calling: parseMessageFromBytes for MessageType: " + type.name());
        }

    }

    //
    // PRIVATE
    //

    static boolean deviceIsTrezor(UsbDevice usbDevice) {
        // no usable interfaces
        if (usbDevice.getInterfaceCount() <= 0) {
            return false;
        }
        // Trezor v1
        if (usbDevice.getVendorId() == 0x534c) {
            return usbDevice.getProductId() == 0x0001;
        }
        // Trezor v2
        if (usbDevice.getVendorId() == 0x1209) {
            return usbDevice.getProductId() == 0x53c0 || usbDevice.getProductId() == 0x53c1;
        }
        return false;
    }

    private TrezorDevice tryGetDevice() {
        if (device == null) {
            Timber.i(TAG, "tryGetDevice: trying to find and open connection to Trezor");
            HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();

            deviceWithoutPermission = null;

            for (UsbDevice usbDevice : deviceList.values()) {
                // check if the device is Trezor
                if (!deviceIsTrezor(usbDevice))
                    continue;

                Timber.i(TAG, "tryGetDevice: Trezor device found");

                if (!usbManager.hasPermission(usbDevice)) {
                    if (deviceWithoutPermission == null)
                        deviceWithoutPermission = usbDevice;
                    continue;
                }

                // use first interface
                UsbInterface usbInterface = usbDevice.getInterface(0);
                // try to find read/write endpoints
                UsbEndpoint readEndpoint = null, writeEndpoint = null;
                for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                    UsbEndpoint ep = usbInterface.getEndpoint(i);
                    if (readEndpoint == null && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT && ep.getAddress() == 0x81) { // number = 1 ; dir = USB_DIR_IN
                        readEndpoint = ep;
                        continue;
                    }
                    if (writeEndpoint == null && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT && (ep.getAddress() == 0x01 || ep.getAddress() == 0x02)) { // number = 1 ; dir = USB_DIR_OUT
                        writeEndpoint = ep;
                    }
                }
                if (readEndpoint == null) {
                    Timber.e(TAG, "tryGetDevice: Could not find read endpoint");
                    continue;
                }
                if (writeEndpoint == null) {
                    Timber.e(TAG, "tryGetDevice: Could not find write endpoint");
                    continue;
                }
                if (readEndpoint.getMaxPacketSize() != 64) {
                    Timber.e(TAG, "tryGetDevice: Wrong packet size for read endpoint");
                    continue;
                }
                if (writeEndpoint.getMaxPacketSize() != 64) {
                    Timber.e(TAG, "tryGetDevice: Wrong packet size for write endpoint");
                    continue;
                }

                UsbDeviceConnection conn = usbManager.openDevice(usbDevice);
                if (conn == null) {
                    Timber.e(TAG, "tryGetDevice: could not open connection");
                } else {
                    if (!conn.claimInterface(usbInterface, true)) {
                        Timber.e(TAG, "tryGetDevice: could not claim interface");
                    } else {
                        deviceWithoutPermission = null;
                        device = new TrezorDevice(usbDevice.getDeviceName(), conn.getSerial(), conn, usbInterface, readEndpoint, writeEndpoint);
                        break;
                    }
                }
            }
            Timber.i(TAG, "tryGetDevice: " + (this.device == null ? "Trezor device not found or failed to connect" : "Trezor device successfully connected"));
        } else
            Timber.i(TAG, "tryGetDevice: using already connected device");
        return device;
    }

    //
    // INNER CLASSES
    //

    private static class TrezorDevice {
        private static final String TAG = TrezorDevice.class.getSimpleName();

        private final String deviceName;
        private final String serial;

        // next fields are only valid until calling close()
        private UsbDeviceConnection usbConnection;
        private UsbInterface usbInterface;
        private UsbEndpoint readEndpoint;
        private UsbEndpoint writeEndpoint;

        TrezorDevice(String deviceName,
                     String serial,
                     UsbDeviceConnection usbConnection,
                     UsbInterface usbInterface,
                     UsbEndpoint readEndpoint,
                     UsbEndpoint writeEndpoint) {
            this.deviceName = deviceName;
            this.serial = serial;
            this.usbConnection = usbConnection;
            this.usbInterface = usbInterface;
            this.readEndpoint = readEndpoint;
            this.writeEndpoint = writeEndpoint;
        }

        @Override
        public String toString() {
            return "TREZOR(path:" + this.deviceName + " serial:" + this.serial + ")";
        }

        Message sendMessage(Message msg) throws InvalidProtocolBufferException {
            if (usbConnection == null)
                throw new IllegalStateException(TAG + ": sendMessage: usbConnection already closed, cannot send message");

            messageWrite(msg);
            return messageRead();
        }

        void close() {
            if (this.usbConnection != null) {
                try {
                    usbConnection.releaseInterface(usbInterface);
                }
                catch (Exception ex) {}
                try {
                    usbConnection.close();
                }
                catch (Exception ex) {}

                usbConnection = null;
                usbInterface = null;
                readEndpoint = null;
                writeEndpoint = null;
            }
        }

        //
        // PRIVATE
        //

        private void messageWrite(Message msg) {
            int msg_size = msg.getSerializedSize();
            String msg_name = msg.getClass().getSimpleName();
            int msg_id = MessageType.valueOf("MessageType_" + msg_name).getNumber();
            Timber.i(TAG, String.format("messageWrite: Got message: %s (%d bytes)", msg_name, msg_size));
            ByteBuffer data = ByteBuffer.allocate(msg_size + 1024); // 32768);
            data.put((byte) '#');
            data.put((byte) '#');
            data.put((byte) ((msg_id >> 8) & 0xFF));
            data.put((byte) (msg_id & 0xFF));
            data.put((byte) ((msg_size >> 24) & 0xFF));
            data.put((byte) ((msg_size >> 16) & 0xFF));
            data.put((byte) ((msg_size >> 8) & 0xFF));
            data.put((byte) (msg_size & 0xFF));
            data.put(msg.toByteArray());
            while (data.position() % 63 > 0) {
                data.put((byte) 0);
            }
            UsbRequest request = new UsbRequest();
            request.initialize(usbConnection, writeEndpoint);
            int chunks = data.position() / 63;
            Timber.i(TAG, String.format("messageWrite: Writing %d chunks", chunks));
            data.rewind();
            for (int i = 0; i < chunks; i++) {
                byte[] buffer = new byte[64];
                buffer[0] = (byte) '?';
                data.get(buffer, 1, 63);
                request.queue(ByteBuffer.wrap(buffer), 64);
                usbConnection.requestWait();
            }
        }

        private Message messageRead() throws InvalidProtocolBufferException {
            ByteBuffer data = null;//ByteBuffer.allocate(32768);
            ByteBuffer buffer = ByteBuffer.allocate(64);
            UsbRequest request = new UsbRequest();
            request.initialize(usbConnection, readEndpoint);
            MessageType type;
            int msg_size;
            int invalidChunksCounter = 0;

            for (; ; ) {
                request.queue(buffer, 64);
                usbConnection.requestWait();
                byte[] b = buffer.array();
                Timber.i(TAG, String.format("messageRead: Read chunk: %d bytes", b.length));

                if (b.length < 9 || b[0] != (byte) '?' || b[1] != (byte) '#' || b[2] != (byte) '#') {
                    if (invalidChunksCounter++ > 5)
                        throw new InvalidProtocolBufferException("messageRead: too many invalid chunks");
                    continue;
                }

                type = MessageType.valueOf((((int)b[3] & 0xFF) << 8) + ((int)b[4] & 0xFF));
                msg_size = (((int)b[5] & 0xFF) << 24)
                        + (((int)b[6] & 0xFF) << 16)
                        + (((int)b[7] & 0xFF) << 8)
                        + ((int)b[8] & 0xFF);
                data = ByteBuffer.allocate(msg_size + 1024);
                data.put(b, 9, b.length - 9);
                break;
            }

            invalidChunksCounter = 0;

            while (data.position() < msg_size) {
                request.queue(buffer, 64);
                usbConnection.requestWait();
                byte[] b = buffer.array();
                Timber.i(TAG, String.format("messageRead: Read chunk (cont): %d bytes", b.length));
                if (b[0] != (byte) '?') {
                    if (invalidChunksCounter++ > 5)
                        throw new InvalidProtocolBufferException("messageRead: too many invalid chunks (2)");
                    continue;
                }
                data.put(b, 1, b.length - 1);
            }

            byte[] msgData = Arrays.copyOfRange(data.array(), 0, msg_size);

            Timber.i(TAG, String.format("parseMessageFromBytes: Parsing %s (%d bytes):", type, msgData.length));
            return parseMessageFromBytes(type, msgData);
        }
    }


    public static abstract class UsbPermissionReceiver extends BaseBroadcastReceivers.BaseGlobalReceiver {
        public static final String ACTION = UsbPermissionReceiver.class.getName() + ".ACTION";

        public UsbPermissionReceiver() {
            super(ACTION);
        }

        @Override
        protected final void onReceiveRegistered(Context context, Intent intent) {
            boolean granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
            onUsbPermissionResult(granted);
        }

        public abstract void onUsbPermissionResult(boolean granted);
    }


    public static abstract class TrezorConnectionChangedReceiver extends BaseBroadcastReceivers.BaseGlobalReceiver {
        private static final String TAG = TrezorConnectionChangedReceiver.class.getSimpleName();

        private static IntentFilter createIntentFilter() {
            IntentFilter ret = new IntentFilter();
            ret.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
            ret.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
            return ret;
        }

        public TrezorConnectionChangedReceiver() {
            super(createIntentFilter());
        }

        @Override
        protected final void onReceiveRegistered(Context context, Intent intent) {
            Timber.d(TAG, "onReceiveRegistered: " + intent.getAction());

            UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            if (device != null && deviceIsTrezor(device)) {
                if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction()))
                    onTrezorConnectionChanged(true);
                else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
                    onTrezorConnectionChanged(false);
                }
            }
        }

        public abstract void onTrezorConnectionChanged(boolean connected);
    }
}
import android.os.Parcel;
import com.circlegate.liban.base.ApiBase.ApiCreator;
import com.circlegate.liban.base.ApiBase.ApiParcelable;
import com.circlegate.liban.base.ApiBase.IApiParcelable;
import com.circlegate.liban.base.ApiDataIO.ApiDataInput;
import com.circlegate.liban.base.ApiDataIO.ApiDataOutput;
import com.circlegate.liban.task.TaskCommon.TaskParam;
import com.circlegate.liban.task.TaskCommon.TaskResult;
import com.circlegate.liban.task.TaskErrors.BaseError;
import com.circlegate.liban.task.TaskErrors.ITaskError;
import com.circlegate.liban.task.TaskErrors.TaskError;
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.ITaskResult;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.satoshilabs.trezor.app.R;
import com.satoshilabs.trezor.lib.TrezorException;
import com.satoshilabs.trezor.lib.TrezorManager;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessage.MessageType;
package com.satoshilabs.trezor.app.common;



public class TrezorTasks {
    public interface ITrezorTaskParam extends ITaskParam, IApiParcelable {
        String SERIAL_EXECUTION_KEY_TREZOR = "trezor";

        MsgWrp getMsgParam();
    }

    public interface ITrezorTaskResult extends ITaskResult, IApiParcelable {
        ITrezorTaskParam getParam();
        MsgWrp getMsgResult();
    }


    public static class TrezorError extends TaskError {
        public static final TrezorError ERR_NOT_CONNECTED = new TrezorError(TrezorException.TYPE_NOT_CONNECTED, R.string.trezor_err_not_connected);
        public static final TrezorError ERR_NEEDS_PERMISSION = new TrezorError(TrezorException.TYPE_NEEDS_PERMISSION, R.string.trezor_err_needs_permission);
        public static final TrezorError ERR_COMMUNICATION_ERROR = new TrezorError(TrezorException.TYPE_COMMUNICATION_ERROR, R.string.trezor_err_communication_error);
        public static final TrezorError ERR_UNEXPECTED_RESPONSE = new TrezorError(TrezorException.TYPE_UNEXPECTED_RESPONSE, R.string.trezor_err_unexpected_response);
        // POZOR pri pridavani nezapominat pridavat case radky do tryGetTrezorError()

        private static TrezorError tryGetTrezorError(int type) {
            switch (type) {
                case TrezorException.TYPE_NOT_CONNECTED: return ERR_NOT_CONNECTED;
                case TrezorException.TYPE_NEEDS_PERMISSION: return ERR_NEEDS_PERMISSION;
                case TrezorException.TYPE_COMMUNICATION_ERROR: return ERR_COMMUNICATION_ERROR;
                case TrezorException.TYPE_UNEXPECTED_RESPONSE: return ERR_UNEXPECTED_RESPONSE;
                default: return null;
            }
        }


        private final int type;
        private final int msgRid;

        public static ITaskError getErrorFromException(TrezorException ex) {