package com.luticate.utils.business;

import com.luticate.utils.dbo.LuDbo;
import com.luticate.utils.dbo.LuMultipleDbo;

/**
 *
 * Created by robin on 11/27/15.
 */
public class LuPromise<T> {

    public interface LuConsumer<T> {
        void execute(T data);
    }

    public interface LuConverter<T, T2> {
        T2 convert(T data);
    }

    public static class LuPromiseError {

        public LuPromiseError()
        {

        }

        public LuPromiseError(String error, int statusCode)
        {
            _error = error;
            _statusCode = statusCode;
        }

        public String getError() {
            return _error;
        }

        public void setError(String error) {
            _error = error;
        }

        public int getStatusCode() {
            return _statusCode;
        }

        public void setStatusCode(int statusCode) {
            _statusCode = statusCode;
        }

        private String _error;

        private int _statusCode;

        @Override
        public String toString() {
            return _error + " (HTTP Code : " + _statusCode + ")";
        }
    }

    public enum LuPromiseStatus {
        Running,
        Resolved,
        Failed
    }

    private LuConsumer<T> _onSuccess = new LuConsumer<T>() {
        @Override
        public void execute(T data) {
        }
    };

    private LuConsumer<LuPromiseError> _onFailed = new LuConsumer<LuPromiseError>() {
        @Override
        public void execute(LuPromiseError data) {
        }
    };

    private LuPromiseStatus _status = LuPromiseStatus.Running;

    private T _data = null;

    private LuPromiseError _error = null;

    public LuPromise<T> then(LuConsumer<T> onSuccess, LuConsumer<LuPromiseError> onFailed)
    {
        _onFailed = onFailed;
        if (_status == LuPromiseStatus.Failed) {
            _onFailed.execute(_error);
        }
        return then(onSuccess);
    }

    public LuPromise<T> then(LuConsumer<T> onSuccess)
    {
        _onSuccess = onSuccess;
        if (_status == LuPromiseStatus.Resolved) {
            _onSuccess.execute(_data);
        }
        return this;
    }

    public void resolve(T data)
    {
        if (_status == LuPromiseStatus.Running) {
            _data = data;
            _error = null;
            _status = LuPromiseStatus.Resolved;
            _onSuccess.execute(_data);
        }
    }

    public void reject(LuPromiseError error)
    {
        if (_status == LuPromiseStatus.Running) {
            _data = null;
            _error = error;
            _status = LuPromiseStatus.Failed;
            _onFailed.execute(_error);
        }
    }

    public <T2> LuPromise<T2> map(final LuConverter<T, T2> converter)
    {
        final LuPromise<T2> promise = new LuPromise<>();
        then(new LuConsumer<T>() {
            @Override
            public void execute(T data) {
                promise.resolve(converter.convert(data));
            }
        }, new LuConsumer<LuPromiseError>() {
            @Override
            public void execute(LuPromiseError error) {
                promise.reject(error);
            }
        });
        return promise;
    }

    public LuConsumer<LuPromiseError> rejectConsumer()
    {
        return new LuConsumer<LuPromiseError>() {
            @Override
            public void execute(LuPromiseError error) {
                reject(error);
            }
        };
    }

    public LuPromiseStatus getStatus()
    {
        return _status;
    }
}
