public interface GetRatesListInteractor {

    void execute(String path, GetRatesListCallback callback) throws CustomException;

    interface GetRatesListCallback {
        void onGetRatesListOK(List<Rate> rateList);

        void onGetRatesListKO(String error);
    }
} public class GetRatesListInteractorImpl implements GetRatesListInteractor, Interactor {

    private InteractorExecutor executor;
    private MainThread mainThread;
    private DataRepository<Rate, Transaction> repository;
    private GetRatesListCallback callback;
    private String path;

    @Inject
    GetRatesListInteractorImpl(InteractorExecutor executor,
                               MainThread mainThread,
                               DataRepository repository) {
        this.executor = executor;
        this.mainThread = mainThread;
        this.repository = repository;
    }

    @Override
    public void execute(String path, GetRatesListCallback callback) throws CustomException {
        this.path = path;
        this.callback = callback;
        this.executor.run(this);
    }

    @Override
    public void run() throws CustomException {
        String errorMessage = "unable to read from file: ";
        try {
            List<Rate> ratesList = repository.getRatesList(path);
            if (ratesList != null) {
                notifySuccessfullyLoaded(ratesList);
            } else {
                notifyError(errorMessage);
            }
        } catch (CustomException e) {
            notifyError(errorMessage + e.getMessage());
        }
    }

    /**
     * <p>Notifies to the UI (main) thread the result of the request,
     * and sends a callback with a list</p>
     */
    private void notifySuccessfullyLoaded(final List<Rate> rateList) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onGetRatesListOK(rateList);
            }
        });
    }

    /**
     * <p>Notifies to the UI (main) thread that an error happened</p>
     */
    private void notifyError(final String error) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onGetRatesListKO(error);
            }
        });
    }
} public interface GetTransactionListInteractor {

    void execute(String path, GetTransactionsListCallback callback) throws CustomException;

    interface GetTransactionsListCallback {
        void onGetTransactionsListOK(List<Transaction> transactionList);

        void onGetTransactionListKO(String error);
    }
} public class GetTransactionListInteractorImpl implements GetTransactionListInteractor, Interactor {

    private InteractorExecutor executor;
    private MainThread mainThread;
    private DataRepository<Rate, Transaction> repository;
    private GetTransactionsListCallback callback;
    private String path;

    @Inject
    GetTransactionListInteractorImpl(InteractorExecutor executor,
                                     MainThread mainThread,
                                     DataRepository repository) {
        this.executor = executor;
        this.mainThread = mainThread;
        this.repository = repository;
    }

    @Override
    public void execute(String path, GetTransactionsListCallback callback) {
        this.path = path;
        this.callback = callback;
        try {
            this.executor.run(this);
        } catch (CustomException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() throws CustomException {
        String errorMessage = "no listing from files ";
        try {
            List<Transaction> transactions = repository.getTransactionsList(path);
            if (transactions != null) {
                notifySuccessfullyLoaded(transactions);
            } else {
                notifyError(errorMessage);
            }
        } catch (CustomException e) {
            notifyError(errorMessage + e.getMessage());
        }
    }

    /**
     * <p>Notifies to the UI (main) thread the corresponding callback with a corresponding movie detail</p>
     */
    private void notifySuccessfullyLoaded(final List<Transaction> transactions) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onGetTransactionsListOK(transactions);
            }
        });
    }

    /**
     * <p>Notifies to the UI (main) thread that an error has happened</p>
     */
    private void notifyError(final String error) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onGetTransactionListKO(error);
            }
        });
    }
} public class SavedTransactionListInteractorImpl implements SavedTransactionsListInteractor, Interactor {

    private InteractorExecutor executor;
    private MainThread mainThread;
    private DataRepository<Rate, Transaction> repository;
    private Map<String, List<Transaction>> map;
    private SavedTransactionsCallback callback;

    @Inject
    SavedTransactionListInteractorImpl(InteractorExecutor executor,
                                       MainThread mainThread,
                                       DataRepository repository) {
        this.executor = executor;
        this.mainThread = mainThread;
        this.repository = repository;
    }

    @Override
    public void executeSaveTransactions(Map<String, List<Transaction>> transactionDictionary,
                                        SavedTransactionsCallback savedTransactionsCallback) throws CustomException {
        this.map = transactionDictionary;
        this.callback = savedTransactionsCallback;
        this.executor.run(this);
    }

    @Override
    public void run() throws CustomException {
        if (repository.saveTransactions(map)) {
            notifySuccessfullySaved("Transactions were saved succesfully.");
        } else {
            notifyError("Transactions were not saved properly.");
        }
    }


    /**
     * <p>Notifies to the UI (main) thread the corresponding callback</p>
     */
    private void notifySuccessfullySaved(final String msg) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onSavedTransactionsListOK(msg);
            }
        });
    }

    /**
     * <p>Notifies to the UI (main) thread that an error has happened</p>
     */
    private void notifyError(final String errorMessage) {
        mainThread.post(new Runnable() {
            @Override
            public void run() {
                callback.onSavedTransactionsListKO(errorMessage);
            }
        });
    }
} public interface SavedTransactionsListInteractor {
    void executeSaveTransactions(Map<String, List<Transaction>> transactionList,
                                 SavedTransactionsCallback savedTransactionsCallback) throws CustomException;

    interface SavedTransactionsCallback {
        void onSavedTransactionsListOK(String msg);

        void onSavedTransactionsListKO(String error);
    }
} public interface RatesPresenter {

    void startReading(String path) throws CustomException;

    void setView(View view);

    void resetView();

    interface View {
        void errorGettingRates(String error);

        void loadedRates(List<RateUI> listOfRates);

        boolean isReady();
    }
} public class RatesPresenterImpl implements RatesPresenter {

    private final GetRatesListInteractor interactorGetRatesList;
    private final RatesListModelDataMapper ratesListModelDataMapper;
    private View view;

    @Inject
    RatesPresenterImpl(
            GetRatesListInteractor interactorGetRatesList,
            RatesListModelDataMapper ratesListModelDataMapper) {
        this.interactorGetRatesList = interactorGetRatesList;
        this.ratesListModelDataMapper = ratesListModelDataMapper;
    }

    @Override
    public void setView(View view) {
        if (view == null) {
            throw new IllegalArgumentException("The view should be instantiated");
        }
        this.view = view;
    }

    @Override
    public void resetView() {
        view = null;
    }

    @Override
    public void startReading(String path) throws CustomException {
        if (view != null) {
            startGettingRatesListFromJSON(path);
        }
    }

    private void startGettingRatesListFromJSON(String path) throws CustomException {
        interactorGetRatesList.execute(
                path, new GetRatesListCallbackImpl(view, ratesListModelDataMapper));
    }
} public interface TransactionsPresenter {
    void startReading(String path) throws CustomException;

    void setView(View view);

    void saveProducts(List<Transaction> transactionList, Map<String, List<Transaction>> transactionsMap)
            throws CustomException;

    void resetView();

    interface View {
        void saveProducts(Map<String, List<Transaction>> transactionsMap, List<Transaction> transactionList);

        void errorSavingProducts(String error);

        void productsSavedSuccessfully(String msg);

        void errorGettingTransactions(String error);

        void showProductsList(List<ProductUI> productUIs);

        void showEmptyState();

        boolean isReady();
    }
} public class TransactionsPresenterImpl implements TransactionsPresenter {

    private final GetTransactionListInteractor interactor;
    private final SavedTransactionsListInteractor interactorSaver;
    private final TransactionsListModelDataMapper transactionsListModelDataMapper;
    private View view;

    @Inject
    TransactionsPresenterImpl(
            GetTransactionListInteractor interactor,
            SavedTransactionsListInteractor interactorSaver,
            TransactionsListModelDataMapper transactionsListModelDataMapper) {
        this.transactionsListModelDataMapper = transactionsListModelDataMapper;
        this.interactor = interactor;
        this.interactorSaver = interactorSaver;
    }

    @Override
    public void startReading(String path) throws CustomException {
        if (view != null) {
            startGettingTransactionsListFromJSON(path);
        }
    }

    private void startGettingTransactionsListFromJSON(String path) throws CustomException {
        interactor.execute(path, new GetTransactionsListCallbackImpl(view, transactionsListModelDataMapper));
    }

    @Override
    public void setView(View view) {
        if (view == null) {
            throw new IllegalArgumentException("The view should be instantiated");
        }
        this.view = view;
    }

    @Override
    public void saveProducts(List<Transaction> transactionList, Map<String, List<Transaction>> transactionsMap)
            throws CustomException {
        if (view != null) {
            List<ProductUI> productUIs = transactionsListModelDataMapper.transform(transactionsMap);
            interactorSaver.executeSaveTransactions(transactionsMap, new SavedTransactionsCallbackImpl(view));
            showProducts(productUIs);
        }
    }

    private void showProducts(List<ProductUI> productUIs) {
        if (productUIs.size() > 0) {
            view.showProductsList(productUIs);
        } else {
            view.showEmptyState();
        }
    }

    @Override
    public void resetView() {
        view = null;
    }
}
import com.raulh82vlc.TransactionsViewer.di.scopes.ActivityScope;
import com.raulh82vlc.TransactionsViewer.domain.interactors.GetRatesListInteractor;
import com.raulh82vlc.TransactionsViewer.domain.interactors.GetRatesListInteractorImpl;
import com.raulh82vlc.TransactionsViewer.domain.interactors.GetTransactionListInteractor;
import com.raulh82vlc.TransactionsViewer.domain.interactors.GetTransactionListInteractorImpl;
import com.raulh82vlc.TransactionsViewer.domain.interactors.SavedTransactionListInteractorImpl;
import com.raulh82vlc.TransactionsViewer.domain.interactors.SavedTransactionsListInteractor;
import com.raulh82vlc.TransactionsViewer.ui.presentation.RatesPresenter;
import com.raulh82vlc.TransactionsViewer.ui.presentation.RatesPresenterImpl;
import com.raulh82vlc.TransactionsViewer.ui.presentation.TransactionsPresenter;
import com.raulh82vlc.TransactionsViewer.ui.presentation.TransactionsPresenterImpl;
import dagger.Module;
import dagger.Provides;
/*
 * Copyright (C) 2017 Raul Hernandez Lopez @raulh82vlc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.raulh82vlc.TransactionsViewer.di.modules;



/**
 * Module which provides all user required artifacts
 * (presenter, interactors, repository, datasources or mappers)
 * in order to use them in a decoupled way
 *
 * @author Raul Hernandez Lopez
 */
@Module
public class ProductsListModule {

    @Provides
    @ActivityScope
    GetRatesListInteractor provideGetRatesListInteractor(GetRatesListInteractorImpl interactor) {
        return interactor;
    }

    @Provides
    @ActivityScope
    RatesPresenter provideRatesPresenter(RatesPresenterImpl presenter) {
        return presenter;
    }

    @Provides
    @ActivityScope
    GetTransactionListInteractor provideGetTransactionListInteractor(GetTransactionListInteractorImpl interactor) {
        return interactor;
    }

    @Provides
    @ActivityScope
    SavedTransactionsListInteractor provideSaveTransactionsListInteractor(SavedTransactionListInteractorImpl
                                                                                  interactor) {
        return interactor;
    }

    @Provides
    @ActivityScope
    TransactionsPresenter provideTransactionsPresenter(TransactionsPresenterImpl presenter) {