de.geeksfactory.opacclient.frontend.AccountFragment.java Source code

Java tutorial

Introduction

Here is the source code for de.geeksfactory.opacclient.frontend.AccountFragment.java

Source

/**
 * Copyright (C) 2013 by Raphael Michel under the MIT license:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package de.geeksfactory.opacclient.frontend;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.apache.http.NoHttpResponseException;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.json.JSONException;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import de.geeksfactory.opacclient.OpacClient;
import de.geeksfactory.opacclient.R;
import de.geeksfactory.opacclient.apis.EbookServiceApi;
import de.geeksfactory.opacclient.apis.EbookServiceApi.BookingResult;
import de.geeksfactory.opacclient.apis.OpacApi;
import de.geeksfactory.opacclient.apis.OpacApi.CancelResult;
import de.geeksfactory.opacclient.apis.OpacApi.MultiStepResult;
import de.geeksfactory.opacclient.apis.OpacApi.OpacErrorException;
import de.geeksfactory.opacclient.apis.OpacApi.ProlongAllResult;
import de.geeksfactory.opacclient.apis.OpacApi.ProlongResult;
import de.geeksfactory.opacclient.apis.OpacApi.ReservationResult;
import de.geeksfactory.opacclient.frontend.MultiStepResultHelper.Callback;
import de.geeksfactory.opacclient.frontend.MultiStepResultHelper.StepTask;
import de.geeksfactory.opacclient.frontend.OpacActivity.AccountSelectedListener;
import de.geeksfactory.opacclient.frontend.adapter.AccountAdapter;
import de.geeksfactory.opacclient.frontend.adapter.LentAdapter;
import de.geeksfactory.opacclient.frontend.adapter.ReservationsAdapter;
import de.geeksfactory.opacclient.networking.NotReachableException;
import de.geeksfactory.opacclient.networking.SSLSecurityException;
import de.geeksfactory.opacclient.objects.Account;
import de.geeksfactory.opacclient.objects.AccountData;
import de.geeksfactory.opacclient.objects.AccountItem;
import de.geeksfactory.opacclient.objects.DetailledItem;
import de.geeksfactory.opacclient.objects.LentItem;
import de.geeksfactory.opacclient.objects.Library;
import de.geeksfactory.opacclient.objects.ReservedItem;
import de.geeksfactory.opacclient.reminder.ReminderHelper;
import de.geeksfactory.opacclient.reminder.SyncAccountAlarmListener;
import de.geeksfactory.opacclient.storage.AccountDataSource;
import de.geeksfactory.opacclient.ui.AccountDividerItemDecoration;
import de.geeksfactory.opacclient.utils.ErrorReporter;
import su.j2e.rvjoiner.JoinableAdapter;
import su.j2e.rvjoiner.JoinableLayout;
import su.j2e.rvjoiner.RvJoiner;

public class AccountFragment extends Fragment
        implements AccountSelectedListener, LentAdapter.Callback, ReservationsAdapter.Callback {

    public static final long MAX_CACHE_AGE = (1000 * 3600 * 2);
    private static final int REQUEST_DETAIL = 1;
    protected AlertDialog adialog;
    protected OpacClient app;
    protected View view;
    protected FrameLayout errorView;
    protected View unsupportedErrorView, answerErrorView;
    protected SwipeRefreshLayout swipeRefreshLayout;
    protected Button btSend, btPrefs;
    protected LinearLayout llLoading;
    protected TextView tvError, tvResHeader, tvPendingFeesLabel, tvPendingFees, tvValidUntilLabel, tvValidUntil,
            tvAge, tvLentHeader, tvWarning, tvAccCity, tvAccUser, tvAccLabel, tvErrBodyA, tvErrHeadA, tvErrBodyU;
    protected LentAdapter lentAdapter;
    protected ReservationsAdapter resAdapter;
    protected AccountData accountData;
    private LoadTask lt;
    private CancelTask ct;
    private DownloadTask dt;
    private Account account;
    private boolean refreshing = false;
    private long refreshtime;
    private boolean fromcache;
    private boolean supported = true;
    private JoinableLayout lentEmpty;
    private JoinableLayout reservationsEmpty;
    private TextView tvLentEmpty;
    private TextView tvReservationsEmpty;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        view = inflater.inflate(R.layout.fragment_account, container, false);
        app = (OpacClient) getActivity().getApplication();
        account = app.getAccount();
        findViews();

        swipeRefreshLayout.setColorSchemeResources(R.color.primary_red);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refresh();
            }
        });

        setHasOptionsMenu(true);

        final Handler handler = new Handler();
        // schedule alarm here and post runnable as soon as scheduled
        handler.post(new Runnable() {
            @Override
            public void run() {
                displayAge();
                handler.postDelayed(this, 60000);
            }
        });

        return view;
    }

    private void findViews() {
        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
        errorView = (FrameLayout) view.findViewById(R.id.error_view);
        unsupportedErrorView = view.findViewById(R.id.unsupported_error);
        answerErrorView = view.findViewById(R.id.answer_error);
        llLoading = (LinearLayout) view.findViewById(R.id.llLoading);
        tvErrBodyU = (TextView) view.findViewById(R.id.tvErrBodyU);
        btSend = (Button) view.findViewById(R.id.btSend);
        btPrefs = (Button) view.findViewById(R.id.btPrefs);
        tvErrHeadA = (TextView) view.findViewById(R.id.tvErrHeadA);
        tvErrBodyA = (TextView) view.findViewById(R.id.tvErrBodyA);
        tvLentEmpty = (TextView) view.findViewById(R.id.emptyLent);
        tvReservationsEmpty = (TextView) view.findViewById(R.id.emptyReservations);

        lentAdapter = new LentAdapter(this);
        try {
            lentAdapter.setApi(app.getApi());
        } catch (OpacClient.LibraryRemovedException e) {
            e.printStackTrace();
        }
        displayLentItems();
        resAdapter = new ReservationsAdapter(this);
        try {
            resAdapter.setApi(app.getApi());
        } catch (OpacClient.LibraryRemovedException e) {
            e.printStackTrace();
        }
        displayReservedItems();

        if (view.findViewById(R.id.rlAccHeader) != null) {
            // tablet
            RecyclerView rvLent = (RecyclerView) view.findViewById(R.id.rvLent);
            rvLent.setLayoutManager(new LinearLayoutManager(getActivity()));
            rvLent.setAdapter(lentAdapter);
            rvLent.addItemDecoration(new AccountDividerItemDecoration(getContext(), null));

            RecyclerView rvReservations = (RecyclerView) view.findViewById(R.id.rvReservations);
            rvReservations.setLayoutManager(new LinearLayoutManager(getActivity()));
            rvReservations.setAdapter(resAdapter);
            rvReservations.addItemDecoration(new AccountDividerItemDecoration(getContext(), null));

            findHeaderViews(view);
            findErrorWarningViews(view);
            findLentHeader(view);
            findResHeader(view);
            findFooterViews(view);
        } else {
            // phone
            RecyclerView rv = (RecyclerView) view.findViewById(R.id.rvAccountData);
            rv.setLayoutManager(new LinearLayoutManager(getActivity()));
            RvJoiner joiner = new RvJoiner();
            rv.addItemDecoration(new AccountDividerItemDecoration(getContext(), joiner));

            joiner.add(new JoinableLayout(R.layout.account_header, new JoinableLayout.Callback() {
                @Override
                public void onInflateComplete(View view, ViewGroup parent) {
                    findHeaderViews(view);
                }
            }));
            joiner.add(new JoinableLayout(R.layout.account_error_warning, new JoinableLayout.Callback() {
                @Override
                public void onInflateComplete(View view, ViewGroup parent) {
                    findErrorWarningViews(view);
                }
            }));
            joiner.add(new JoinableLayout(R.layout.account_header_lent, new JoinableLayout.Callback() {
                @Override
                public void onInflateComplete(View view, ViewGroup parent) {
                    findLentHeader(view);
                }
            }));
            lentEmpty = new JoinableLayout(R.layout.listitem_account_empty_lent);
            joiner.add(lentEmpty);
            joiner.add(new JoinableAdapter(lentAdapter));
            joiner.add(new JoinableLayout(R.layout.account_header_reservations, new JoinableLayout.Callback() {
                @Override
                public void onInflateComplete(View view, ViewGroup parent) {
                    findResHeader(view);
                }
            }));
            joiner.add(new JoinableAdapter(resAdapter));
            reservationsEmpty = new JoinableLayout(R.layout.listitem_account_empty_reservations);
            joiner.add(reservationsEmpty);
            joiner.add(new JoinableLayout(R.layout.account_footer, new JoinableLayout.Callback() {
                @Override
                public void onInflateComplete(View view, ViewGroup parent) {
                    findFooterViews(view);
                }
            }));

            rv.setAdapter(joiner.getAdapter());
        }
    }

    private void findFooterViews(View view) {
        tvAge = (TextView) view.findViewById(R.id.tvAge);
        displayAge();
    }

    private void findResHeader(View view) {
        tvResHeader = (TextView) view.findViewById(R.id.tvResHeader);
        displayResHeader();
    }

    private void findLentHeader(View view) {
        tvLentHeader = (TextView) view.findViewById(R.id.tvLentHeader);
        displayLentHeader();
    }

    private void findErrorWarningViews(View view) {
        tvError = (TextView) view.findViewById(R.id.tvError);
        tvWarning = (TextView) view.findViewById(R.id.tvWarning);
    }

    private void findHeaderViews(View view) {
        tvAccLabel = (TextView) view.findViewById(R.id.tvAccLabel);
        tvAccUser = (TextView) view.findViewById(R.id.tvAccUser);
        tvAccCity = (TextView) view.findViewById(R.id.tvAccCity);
        tvPendingFeesLabel = (TextView) view.findViewById(R.id.tvPendingFeesLabel);
        tvPendingFees = (TextView) view.findViewById(R.id.tvPendingFees);
        tvValidUntilLabel = (TextView) view.findViewById(R.id.tvValidUntilLabel);
        tvValidUntil = (TextView) view.findViewById(R.id.tvValidUntil);
        displayHeader();
    }

    @SuppressLint("NewApi")
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.activity_account, menu);
        OpacApi api;
        try {
            api = app.getApi();
        } catch (OpacClient.LibraryRemovedException e) {
            return;
        }
        if (app.getAccount() != null && (api.getSupportFlags() & OpacApi.SUPPORT_FLAG_ACCOUNT_PROLONG_ALL) != 0) {
            menu.findItem(R.id.action_prolong_all).setVisible(true);
        } else {
            menu.findItem(R.id.action_prolong_all).setVisible(false);
        }
        menu.findItem(R.id.action_refresh).setVisible(supported);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_refresh) {
            refresh();
        } else if (item.getItemId() == R.id.action_prolong_all) {
            prolongAllStart();
        } else if (item.getItemId() == R.id.action_export) {
            export();
        }
        return super.onOptionsItemSelected(item);
    }

    private void export() {
        if (refreshing) {
            Toast.makeText(getActivity(), R.string.account_no_concurrent, Toast.LENGTH_LONG).show();
            if (!refreshing) {
                refresh();
            }
            return;
        }

        Context ctx = getActivity() != null ? getActivity() : OpacClient.getEmergencyContext();
        AccountDataSource adatasource = new AccountDataSource(ctx);
        AccountData data = adatasource.getCachedAccountData(account);
        LocalDateTime dt = new LocalDateTime(adatasource.getCachedAccountDataTime(account));

        if (data == null)
            return;

        StringBuilder string = new StringBuilder();

        DateTimeFormatter fmt1 = DateTimeFormat.shortDateTime()
                .withLocale(getResources().getConfiguration().locale);
        DateTimeFormatter fmt2 = DateTimeFormat.shortDate().withLocale(getResources().getConfiguration().locale);
        String dateStr = fmt1.print(dt);
        string.append(getResources().getString(R.string.accountdata_export_header, account.getLabel(), dateStr));
        string.append("\n\n");
        string.append(getResources().getString(R.string.lent_head));
        string.append("\n\n");
        for (LentItem item : data.getLent()) {
            appendIfNotEmpty(string, item.getTitle(), R.string.accountdata_title);
            appendIfNotEmpty(string, item.getAuthor(), R.string.accountdata_author);
            appendIfNotEmpty(string, item.getFormat(), R.string.accountdata_format);
            appendIfNotEmpty(string, item.getStatus(), R.string.accountdata_status);
            appendIfNotEmpty(string, item.getBarcode(), R.string.accountdata_lent_barcode);
            if (item.getDeadline() != null) {
                appendIfNotEmpty(string, fmt2.print(item.getDeadline()), R.string.accountdata_lent_deadline);
            }
            appendIfNotEmpty(string, item.getHomeBranch(), R.string.accountdata_lent_home_branch);
            appendIfNotEmpty(string, item.getLendingBranch(), R.string.accountdata_lent_lending_branch);
            string.append("\n");
        }

        if (data.getLent().size() == 0) {
            string.append(getResources().getString(R.string.lent_none));
        }

        string.append(getResources().getString(R.string.reservations_head));
        string.append("\n\n");
        for (ReservedItem item : data.getReservations()) {
            appendIfNotEmpty(string, item.getTitle(), R.string.accountdata_title);
            appendIfNotEmpty(string, item.getAuthor(), R.string.accountdata_author);
            appendIfNotEmpty(string, item.getFormat(), R.string.accountdata_format);
            appendIfNotEmpty(string, item.getStatus(), R.string.accountdata_status);
            if (item.getReadyDate() != null) {
                appendIfNotEmpty(string, fmt2.print(item.getReadyDate()), R.string.accountdata_reserved_ready_date);
            }
            if (item.getExpirationDate() != null) {
                appendIfNotEmpty(string, fmt2.print(item.getExpirationDate()),
                        R.string.accountdata_reserved_expiration_date);
            }
            appendIfNotEmpty(string, item.getBranch(), R.string.accountdata_reserved_branch);
            string.append("\n");
        }

        if (data.getReservations().size() == 0) {
            string.append(getResources().getString(R.string.reservations_none));
        }

        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TEXT, string.toString());
        sendIntent.setType("text/plain");
        startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.share_dialog_select)));
    }

    private void appendIfNotEmpty(StringBuilder string, String text, int id) {
        if (text != null && !text.equals("")) {
            string.append(getResources().getString(id)).append(": ").append(text).append("\n");
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        account = app.getAccount();
        accountSelected(account);
    }

    @Override
    public void accountSelected(Account account) {

        swipeRefreshLayout.setVisibility(View.GONE);
        unsupportedErrorView.setVisibility(View.GONE);
        answerErrorView.setVisibility(View.GONE);
        errorView.removeAllViews();
        llLoading.setVisibility(View.VISIBLE);

        setRefreshing(false);
        supported = true;

        this.account = app.getAccount();
        OpacApi api;
        try {
            api = app.getApi();
        } catch (NullPointerException e) {
            e.printStackTrace();
            return;
        } catch (OpacClient.LibraryRemovedException e) {
            show_connectivity_error(e);
            return;
        }
        if (api != null && !app.getLibrary().isAccountSupported()) {
            supported = false;
            // Not supported with this api at all
            llLoading.setVisibility(View.GONE);
            unsupportedErrorView.setVisibility(View.VISIBLE);
            tvErrBodyU.setText(R.string.account_unsupported_api);
            btSend.setText(R.string.write_mail);
            btSend.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
                    emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { "info@opacapp.de" });
                    emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT,
                            "Bibliothek " + app.getLibrary().getIdent());
                    emailIntent.putExtra(android.content.Intent.EXTRA_TEXT,
                            getResources().getString(R.string.interested_to_help));
                    emailIntent.setType("text/plain");
                    startActivity(Intent.createChooser(emailIntent, getString(R.string.write_mail)));
                }
            });

        } else if (account.getPassword() == null || account.getPassword().equals("null")
                || account.getPassword().equals("") || account.getName() == null || account.getName().equals("null")
                || account.getName().equals("")) {
            // No credentials entered
            llLoading.setVisibility(View.GONE);
            answerErrorView.setVisibility(View.VISIBLE);
            btPrefs.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(getActivity(), AccountEditActivity.class);
                    intent.putExtra(AccountEditActivity.EXTRA_ACCOUNT_ID, app.getAccount().getId());
                    startActivity(intent);
                }
            });
            tvErrHeadA.setText("");
            tvErrBodyA.setText(R.string.status_nouser);

        } else {
            // Supported
            Context ctx = getActivity() != null ? getActivity() : OpacClient.getEmergencyContext();
            AccountDataSource adatasource = new AccountDataSource(ctx);
            refreshtime = adatasource.getCachedAccountDataTime(account);
            if (refreshtime > 0) {
                display(adatasource.getCachedAccountData(account), true);
                if (System.currentTimeMillis() - refreshtime > MAX_CACHE_AGE) {
                    refresh();
                }
            } else {
                refresh();
            }
        }
    }

    public void refresh() {

        if ((!app.getLibrary().isAccountSupported()) || account.getPassword() == null
                || account.getPassword().equals("null") || account.getPassword().equals("")
                || account.getName() == null || account.getName().equals("null") || account.getName().equals("")) {
            return;
        }

        setRefreshing(true);
        lt = new LoadTask();
        lt.execute();
    }

    public void cancel(final String a) {
        long age = System.currentTimeMillis() - refreshtime;
        if (refreshing || fromcache || age > MAX_CACHE_AGE) {
            Toast.makeText(getActivity(), R.string.account_no_concurrent, Toast.LENGTH_LONG).show();
            if (!refreshing) {
                refresh();
            }
            return;
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.cancel_confirm).setCancelable(true)
                .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface d, int id) {
                        d.cancel();
                    }
                }).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface d, int id) {
                        d.dismiss();

                        MultiStepResultHelper<String> msrhCancel = new MultiStepResultHelper<>(getActivity(), a,
                                R.string.doing_cancel);
                        msrhCancel.setCallback(new Callback<String>() {
                            @Override
                            public void onSuccess(MultiStepResult result) {
                                invalidateData();
                            }

                            @Override
                            public void onError(MultiStepResult result) {
                                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                                builder.setMessage(result.getMessage()).setCancelable(true)
                                        .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface d, int id) {
                                                d.cancel();
                                            }
                                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                                            @Override
                                            public void onCancel(DialogInterface d) {
                                                if (d != null) {
                                                    d.cancel();
                                                }
                                            }
                                        });
                                AlertDialog alert = builder.create();
                                alert.show();
                            }

                            @Override
                            public void onUnhandledResult(MultiStepResult result) {
                            }

                            @Override
                            public void onUserCancel() {
                            }

                            @Override
                            public StepTask<?> newTask(MultiStepResultHelper helper, int useraction,
                                    String selection, String argument) {
                                return ct = new CancelTask(helper, useraction, selection, argument);
                            }
                        });
                        msrhCancel.start();
                    }
                }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface d) {
                        if (d != null) {
                            d.cancel();
                        }
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();
    }

    public void prolong(final String a) {
        long age = System.currentTimeMillis() - refreshtime;
        if (refreshing || age > MAX_CACHE_AGE) {
            Toast.makeText(getActivity(), R.string.account_no_concurrent, Toast.LENGTH_LONG).show();
            if (!refreshing) {
                refresh();
            }
            return;
        }
        final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
        OpacApi api;
        try {
            api = app.getApi();
        } catch (OpacClient.LibraryRemovedException e) {
            return;
        }
        if (sp.getBoolean("prolong_fee_warning_ignore", false)
                || (api.getSupportFlags() & OpacApi.SUPPORT_FLAG_WARN_PROLONG_FEES) > 0) {
            prolongPerform(a);
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            View content = getLayoutInflater(null).inflate(R.layout.dialog_prolong_confirm, null);
            final CheckBox check = (CheckBox) content.findViewById(R.id.check_box1);
            builder.setView(content).setCancelable(false)
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    }).setPositiveButton(R.string.reservation_fee_continue, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int id) {
                            if (check.isChecked()) {
                                sp.edit().putBoolean("prolong_fee_warning_ignore", true).apply();
                            }
                            prolongPerform(a);
                        }
                    });
            AlertDialog alert = builder.create();
            alert.show();
        }
    }

    protected void prolongPerform(final String a) {
        MultiStepResultHelper<String> msrhProlong = new MultiStepResultHelper<>(getActivity(), a,
                R.string.doing_prolong);
        msrhProlong.setCallback(new Callback<String>() {
            @Override
            public void onSuccess(MultiStepResult result) {
                if (getActivity() == null) {
                    return;
                }
                invalidateData();

                if (result.getMessage() != null) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                    builder.setMessage(result.getMessage()).setCancelable(false).setNegativeButton(R.string.close,
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int id) {
                                    dialog.cancel();
                                }
                            });
                    AlertDialog alert = builder.create();
                    alert.show();
                }
            }

            @Override
            public void onError(MultiStepResult result) {
                if (getActivity() == null) {
                    return;
                }
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(result.getMessage()).setCancelable(true)
                        .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface d, int id) {
                                d.cancel();
                            }
                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface d) {
                                if (d != null) {
                                    d.cancel();
                                }
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            @Override
            public void onUnhandledResult(MultiStepResult result) {
            }

            @Override
            public void onUserCancel() {
            }

            @Override
            public StepTask<?> newTask(MultiStepResultHelper helper, int useraction, String selection,
                    String argument) {
                return new ProlongTask(helper, useraction, selection, argument);
            }
        });
        msrhProlong.start();

    }

    public void download(final String a) {
        MultiStepResultHelper<String> msrhDownload = new MultiStepResultHelper<>(getActivity(), a,
                R.string.doing_download);
        msrhDownload.setCallback(new Callback<String>() {
            @Override
            public void onSuccess(MultiStepResult res) {
                final EbookServiceApi.DownloadResult result = (EbookServiceApi.DownloadResult) res;
                if (result.getUrl() != null) {
                    if (result.getUrl().contains("acsm")) {
                        String[] download_clients = new String[] { "com.android.aldiko", "com.aldiko.android",
                                "com.bluefirereader", "com.mantano.reader.android.lite", "com.datalogics.dlreader",
                                "com.mantano.reader.android.normal", "com.mantano.reader.android", "com.neosoar" };
                        boolean found = false;
                        PackageManager pm = getActivity().getPackageManager();
                        for (String id : download_clients) {
                            try {
                                pm.getPackageInfo(id, 0);
                                found = true;
                            } catch (NameNotFoundException e) {
                            }
                        }
                        final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
                        if (!found && !sp.contains("reader_needed_ignore")) {
                            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                            builder.setMessage(R.string.reader_needed).setCancelable(true)
                                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int id) {
                                            dialog.cancel();
                                        }
                                    }).setNeutralButton(R.string.reader_needed_ignore,
                                            new DialogInterface.OnClickListener() {
                                                @Override
                                                public void onClick(DialogInterface dialog, int id) {
                                                    Intent i = new Intent(Intent.ACTION_VIEW);
                                                    i.setData(Uri.parse(result.getUrl()));
                                                    sp.edit().putBoolean("reader_needed_ignore", true).commit();
                                                    startActivity(i);
                                                }
                                            })
                                    .setPositiveButton(R.string.download, new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int id) {
                                            dialog.cancel();
                                            Intent i = new Intent(Intent.ACTION_VIEW,
                                                    Uri.parse("market://details?id=de" + ".bluefirereader"));
                                            startActivity(i);
                                        }
                                    });
                            AlertDialog alert = builder.create();
                            alert.show();
                            return;
                        }
                    }
                    Intent i = new Intent(Intent.ACTION_VIEW);
                    i.setData(Uri.parse(result.getUrl()));
                    startActivity(i);
                }
            }

            @Override
            public void onError(MultiStepResult result) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(result.getMessage()).setCancelable(true)
                        .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface d, int id) {
                                d.cancel();
                            }
                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface d) {
                                if (d != null) {
                                    d.cancel();
                                }
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            @Override
            public void onUnhandledResult(MultiStepResult result) {
            }

            @Override
            public void onUserCancel() {
            }

            @Override
            public StepTask<?> newTask(MultiStepResultHelper helper, int useraction, String selection,
                    String argument) {
                return dt = new DownloadTask(helper, useraction, selection, argument);
            }
        });
        msrhDownload.start();
    }

    public void setRefreshing(boolean refreshing) {
        this.refreshing = refreshing;
        swipeRefreshLayout.setRefreshing(refreshing);
    }

    public void invalidateData() {
        AccountDataSource adatasource = new AccountDataSource(getActivity());
        adatasource.invalidateCachedAccountData(account);
        swipeRefreshLayout.setVisibility(View.GONE);
        accountSelected(account);
    }

    public void show_connectivity_error(Exception e) {
        if (e != null) {
            e.printStackTrace();
        }
        if (getActivity() == null) {
            return;
        }
        if (e instanceof OpacErrorException) {
            AccountDataSource adatasource = new AccountDataSource(getActivity());
            adatasource.invalidateCachedAccountData(account);
            dialog_wrong_credentials(e.getMessage());
            return;
        }
        if (getView() != null) {
            final FrameLayout errorView = (FrameLayout) getView().findViewById(R.id.error_view);
            errorView.removeAllViews();
            View connError = getActivity().getLayoutInflater().inflate(R.layout.error_connectivity, errorView);

            TextView tvErrBody = (TextView) connError.findViewById(R.id.tvErrBody);
            Button btnRetry = (Button) connError.findViewById(R.id.btRetry);
            btnRetry.setVisibility(View.VISIBLE);
            if (e != null && e instanceof SSLSecurityException) {
                tvErrBody.setText(R.string.connection_error_detail_security);
            } else if (e != null && e instanceof NotReachableException) {
                tvErrBody.setText(R.string.connection_error_detail_nre);
            } else if (e != null && e instanceof OpacClient.LibraryRemovedException) {
                tvErrBody.setText(R.string.library_removed_error);
                btnRetry.setVisibility(View.GONE);
            }
            btnRetry.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    refresh();
                }
            });
            llLoading.setVisibility(View.GONE);
            swipeRefreshLayout.setVisibility(View.GONE);
            connError.setVisibility(View.VISIBLE);
        }
    }

    protected void dialog_wrong_credentials(String s) {
        llLoading.setVisibility(View.GONE);
        answerErrorView.setVisibility(View.VISIBLE);
        btPrefs.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), AccountEditActivity.class);
                intent.putExtra(AccountEditActivity.EXTRA_ACCOUNT_ID, account.getId());
                startActivity(intent);
            }
        });
        tvErrBodyA.setText(s);
    }

    public void loaded(final AccountData result) {
        if (result.getAccount() == account.getId()) {
            // The account this data is for is still visible

            setRefreshing(false);

            refreshtime = System.currentTimeMillis();

            display(result, false);
        }

    }

    protected void displayHeader() {
        if (accountData == null || tvAccLabel == null || tvAccUser == null || tvAccCity == null
                || tvPendingFees == null || tvPendingFeesLabel == null || tvValidUntil == null
                || tvValidUntilLabel == null) {
            return;
        }

        tvAccLabel.setText(account.getLabel());
        tvAccUser.setText(account.getName());
        Library lib;
        try {
            lib = app.getLibrary(account.getLibrary());
            tvAccCity.setText(lib.getDisplayName());
        } catch (IOException e) {
            ErrorReporter.handleException(e);
            e.printStackTrace();
        } catch (JSONException e) {
            ErrorReporter.handleException(e);
        }

        if (accountData != null) {
            if (accountData.getPendingFees() != null) {
                tvPendingFeesLabel.setVisibility(View.VISIBLE);
                tvPendingFees.setVisibility(View.VISIBLE);
                tvPendingFees.setText(accountData.getPendingFees());
            } else {
                tvPendingFeesLabel.setVisibility(View.GONE);
                tvPendingFees.setVisibility(View.GONE);
            }
            if (accountData.getValidUntil() != null) {
                tvValidUntilLabel.setVisibility(View.VISIBLE);
                tvValidUntil.setVisibility(View.VISIBLE);
                tvValidUntil.setText(accountData.getValidUntil());
            } else {
                tvValidUntilLabel.setVisibility(View.GONE);
                tvValidUntil.setVisibility(View.GONE);
            }
        }
    }

    protected void displayResHeader() {
        if (accountData != null && tvResHeader != null) {
            tvResHeader.setText(getActivity().getString(R.string.reservations_head) + " ("
                    + accountData.getReservations().size() + ")");
        }
    }

    protected void displayLentHeader() {
        if (accountData != null && tvLentHeader != null) {
            tvLentHeader.setText(
                    getActivity().getString(R.string.lent_head) + " (" + accountData.getLent().size() + ")");
        }
    }

    private void displayWarning() {
        if (accountData != null && tvWarning != null) {
            if (accountData.getWarning() != null && accountData.getWarning().length() > 1) {
                tvWarning.setVisibility(View.VISIBLE);
                tvWarning.setText(accountData.getWarning());
            } else {
                tvWarning.setVisibility(View.GONE);
            }
        }
    }

    public void displayAge() {
        try {
            if (tvAge == null) {
                return;
            }

            long age = System.currentTimeMillis() - refreshtime;
            if (age < 60 * 1000) {
                tvAge.setText(getResources().getString(R.string.account_up_to_date));
            } else if (age < (3600 * 1000)) {
                tvAge.setText(getResources().getQuantityString(R.plurals.account_age_minutes,
                        (int) (age / (60 * 1000)), (int) (age / (60 * 1000))));
            } else if (age < 24 * 3600 * 1000) {
                tvAge.setText(getResources().getQuantityString(R.plurals.account_age_hours,
                        (int) (age / (3600 * 1000)), (int) (age / (3600 * 1000))));

            } else {
                tvAge.setText(getResources().getQuantityString(R.plurals.account_age_days,
                        (int) (age / (24 * 3600 * 1000)), (int) (age / (24 * 3600 * 1000))));
            }
        } catch (java.lang.IllegalStateException e) {
            // as this is called from a handler it may be called
            // without an activity attached to this fragment
            // we do nothing about it
        }
    }

    private void displayReservedItems() {
        if (accountData != null && resAdapter != null) {
            resAdapter.setItems(accountData.getReservations());
        }
    }

    private void displayLentItems() {
        if (accountData != null && lentAdapter != null) {
            lentAdapter.setItems(accountData.getLent());
        }
    }

    public void display(final AccountData result, boolean fromcache) {
        accountData = result;
        if (getActivity() == null) {
            return;
        }
        swipeRefreshLayout.setVisibility(View.VISIBLE);
        llLoading.setVisibility(View.GONE);
        unsupportedErrorView.setVisibility(View.GONE);
        answerErrorView.setVisibility(View.GONE);
        errorView.removeAllViews();

        this.fromcache = fromcache;

        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(app.getApplicationContext());
        displayHeader();

        /*
        Lent items
         */
        final boolean notification_on = sp.getBoolean(SyncAccountAlarmListener.PREF_SYNC_SERVICE, false);
        boolean notification_problems = false;

        displayWarning();
        displayLentHeader();
        displayLentItems();
        if (lentEmpty != null) {
            // phone
            lentEmpty.setVisible(result.getLent().size() == 0);
        } else {
            // tablet
            tvLentEmpty.setVisibility(result.getLent().size() == 0 ? View.VISIBLE : View.GONE);
        }
        for (final LentItem item : result.getLent()) {
            try {
                if (notification_on && item.getDeadline() == null && !item.isEbook()) {
                    notification_problems = true;
                }
            } catch (Exception e) {
                notification_problems = true;
            }
        }

        if (notification_problems) {
            if (tvError != null) {
                tvError.setVisibility(View.VISIBLE);
                tvError.setText(R.string.notification_problems);
            }
        }

        /*
        Reservations
         */
        displayResHeader();
        displayReservedItems();
        if (reservationsEmpty != null) {
            // phone
            reservationsEmpty.setVisible(result.getReservations().size() == 0);
        } else {
            // tablet
            tvReservationsEmpty.setVisibility(result.getReservations().size() == 0 ? View.VISIBLE : View.GONE);
        }
        displayAge();

        boolean hideCovers = true;
        for (LentItem item : result.getLent()) {
            if (item.getMediaType() != null || item.getCover() != null)
                hideCovers = false;
        }
        for (ReservedItem item : result.getReservations()) {
            if (item.getMediaType() != null || item.getCover() != null)
                hideCovers = false;
        }
        lentAdapter.setCoversHidden(hideCovers);
        resAdapter.setCoversHidden(hideCovers);
    }

    public void bookingStart(String booking_info) {
        long age = System.currentTimeMillis() - refreshtime;
        if (refreshing || fromcache || age > MAX_CACHE_AGE) {
            Toast.makeText(getActivity(), R.string.account_no_concurrent, Toast.LENGTH_LONG).show();
            if (!refreshing) {
                refresh();
            }
            return;
        }
        DetailledItem item = new DetailledItem();
        item.setBookable(true);
        item.setBooking_info(booking_info);
        MultiStepResultHelper<DetailledItem> msrhBooking = new MultiStepResultHelper<>(getActivity(), item,
                R.string.doing_booking);
        msrhBooking.setCallback(new Callback<DetailledItem>() {
            @Override
            public void onSuccess(MultiStepResult result) {
                invalidateData();
            }

            @Override
            public void onError(MultiStepResult result) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(result.getMessage()).setCancelable(true)
                        .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface d, int id) {
                                d.cancel();
                            }
                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface d) {
                                if (d != null) {
                                    d.cancel();
                                }
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            @Override
            public void onUnhandledResult(MultiStepResult result) {
            }

            @Override
            public void onUserCancel() {
            }

            @Override
            public StepTask<?> newTask(MultiStepResultHelper helper, int useraction, String selection,
                    DetailledItem argument) {
                return new BookingTask(helper, useraction, selection, argument);
            }
        });
        msrhBooking.start();
    }

    public void prolongAllStart() {
        if (refreshing) {
            Toast.makeText(getActivity(), R.string.account_no_concurrent, Toast.LENGTH_LONG).show();
            if (!refreshing) {
                refresh();
            }
            return;
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.prolong_all_confirm).setCancelable(true)
                .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface d, int id) {
                        d.cancel();
                    }
                }).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface d, int id) {
                        prolongAllDo();
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();

    }

    public void prolongAllDo() {

        MultiStepResultHelper<Void> msrhProlong = new MultiStepResultHelper<>(getActivity(), null,
                R.string.doing_prolong_all);
        msrhProlong.setCallback(new Callback<Void>() {
            @Override
            public void onSuccess(MultiStepResult result) {
                if (getActivity() == null) {
                    return;
                }
                ProlongAllResult res = (ProlongAllResult) result;
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

                if (res.getResults() != null) {
                    LayoutInflater inflater = getLayoutInflater(null);
                    View view = inflater.inflate(R.layout.dialog_simple_list, null, false);

                    ListView lv = (ListView) view.findViewById(R.id.lvBibs);

                    lv.setAdapter(new ProlongAllResultAdapter(getActivity(), res.getResults()));
                    switch (result.getActionIdentifier()) {
                    case ReservationResult.ACTION_BRANCH:
                        builder.setTitle(R.string.branch);
                    }
                    builder.setView(view).setNeutralButton(R.string.close, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int id) {
                            adialog.cancel();
                            invalidateData();
                        }
                    });
                } else {
                    builder.setMessage(result.getMessage()).setCancelable(true)
                            .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface d, int id) {
                                    d.cancel();
                                }
                            }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                                @Override
                                public void onCancel(DialogInterface d) {
                                    if (d != null) {
                                        d.cancel();
                                    }
                                }
                            });
                }
                adialog = builder.create();
                adialog.show();
            }

            @Override
            public void onError(MultiStepResult result) {
                if (getActivity() == null) {
                    return;
                }
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(result.getMessage()).setCancelable(true)
                        .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface d, int id) {
                                d.cancel();
                            }
                        }).setOnCancelListener(new DialogInterface.OnCancelListener() {
                            @Override
                            public void onCancel(DialogInterface d) {
                                if (d != null) {
                                    d.cancel();
                                }
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            @Override
            public void onUnhandledResult(MultiStepResult result) {
            }

            @Override
            public void onUserCancel() {
            }

            @Override
            public StepTask<?> newTask(MultiStepResultHelper helper, int useraction, String selection,
                    Void argument) {
                return new ProlongAllTask(helper, useraction, selection);
            }
        });
        msrhProlong.start();
    }

    @Override
    public void onStop() {
        super.onStop();
        try {
            if (lt != null) {
                if (!lt.isCancelled()) {
                    lt.cancel(true);
                }
            }
            if (ct != null) {
                if (!ct.isCancelled()) {
                    ct.cancel(true);
                }
            }
            if (dt != null) {
                if (!dt.isCancelled()) {
                    dt.cancel(true);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class LoadTask extends AsyncTask<Void, Void, AccountData> {

        private Exception exception;

        @Override
        protected AccountData doInBackground(Void... voids) {
            AccountData data;
            try {
                data = app.getApi().account(account);

                if (data == null) {
                    return null;
                }
            } catch (IOException | OpacErrorException | OpacClient.LibraryRemovedException e) {
                exception = e;
                return null;
            } catch (Exception e) {
                ErrorReporter.handleException(e);
                exception = e;
                return null;
            }

            try {
                // save data
                AccountDataSource adatasource;
                if (getActivity() == null && OpacClient.getEmergencyContext() != null) {
                    adatasource = new AccountDataSource(OpacClient.getEmergencyContext());
                } else {
                    adatasource = new AccountDataSource(getActivity());
                }

                account.setPasswordKnownValid(true);
                adatasource.update(account);
                adatasource.storeCachedAccountData(adatasource.getAccount(data.getAccount()), data);
            } finally {
                new ReminderHelper(app).generateAlarms();
            }

            return data;
        }

        @Override
        protected void onPostExecute(AccountData result) {
            if (exception == null && result != null) {
                loaded(result);
            } else {
                setRefreshing(false);

                show_connectivity_error(exception);
            }
        }
    }

    public class CancelTask extends StepTask<CancelResult> {
        private String itemId;

        public CancelTask(MultiStepResultHelper helper, int useraction, String selection, String itemId) {
            super(helper, useraction, selection);
            this.itemId = itemId;
        }

        @Override
        protected CancelResult doInBackground(Void... voids) {
            try {
                return app.getApi().cancel(itemId, account, useraction, selection);
            } catch (java.net.UnknownHostException | NoHttpResponseException | java.net.SocketException e) {
                e.printStackTrace();
            } catch (Exception e) {
                ErrorReporter.handleException(e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(CancelResult result) {
            if (getActivity() == null) {
                return;
            }

            if (result == null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(R.string.error).setCancelable(true).setNegativeButton(R.string.close,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            super.onPostExecute(result);
        }
    }

    public class DownloadTask extends StepTask<EbookServiceApi.DownloadResult> {
        private String itemId;

        public DownloadTask(MultiStepResultHelper helper, int useraction, String selection, String itemId) {
            super(helper, useraction, selection);
            this.itemId = itemId;
        }

        @Override
        protected EbookServiceApi.DownloadResult doInBackground(Void... voids) {
            try {
                return ((EbookServiceApi) app.getApi()).downloadItem(account, itemId, useraction, selection);
            } catch (java.net.UnknownHostException | NoHttpResponseException | java.net.SocketException e) {
                e.printStackTrace();
            } catch (Exception e) {
                ErrorReporter.handleException(e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(EbookServiceApi.DownloadResult result) {
            if (getActivity() == null) {
                return;
            }
            if (getActivity() == null || result == null) {
                return;
            }
            super.onPostExecute(result);
        }
    }

    public class ProlongTask extends MultiStepResultHelper.StepTask<ProlongResult> {
        private boolean success = true;
        private String itemId;

        public ProlongTask(MultiStepResultHelper helper, int useraction, String selection, String itemId) {
            super(helper, useraction, selection);
            this.itemId = itemId;
        }

        @Override
        protected ProlongResult doInBackground(Void... voids) {
            try {
                ProlongResult res = app.getApi().prolong(itemId, account, useraction, selection);
                success = true;
                return res;
            } catch (java.net.UnknownHostException | NoHttpResponseException e) {
                publishProgress(e, "ioerror");
            } catch (IOException e) {
                success = false;
                e.printStackTrace();
            } catch (Exception e) {
                ErrorReporter.handleException(e);
                success = false;
            }
            return null;
        }

        @Override
        protected void onPostExecute(ProlongResult res) {
            if (getActivity() == null) {
                return;
            }

            super.onPostExecute(res);

            if (!success || res == null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(R.string.error).setCancelable(true).setNegativeButton(R.string.close,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }
        }
    }

    public class ProlongAllTask extends MultiStepResultHelper.StepTask<ProlongAllResult> {

        public ProlongAllTask(MultiStepResultHelper helper, int useraction, String selection) {
            super(helper, useraction, selection);
        }

        @Override
        protected ProlongAllResult doInBackground(Void... voids) {
            try {
                return app.getApi().prolongAll(account, useraction, selection);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                ErrorReporter.handleException(e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(ProlongAllResult result) {
            if (getActivity() == null) {
                return;
            }

            if (result == null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(R.string.error).setCancelable(true).setNegativeButton(R.string.close,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
            }

            super.onPostExecute(result);
        }
    }

    public class ProlongAllResultAdapter extends ArrayAdapter<Map<String, String>> {

        private List<Map<String, String>> objects;

        public ProlongAllResultAdapter(Context context, List<Map<String, String>> objects) {
            super(context, R.layout.simple_spinner_item, objects);
            this.objects = objects;
        }

        @Override
        public View getView(int position, View contentView, ViewGroup viewGroup) {
            View view;

            if (objects.get(position) == null) {
                LayoutInflater layoutInflater = (LayoutInflater) getContext()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = layoutInflater.inflate(R.layout.listitem_prolongall_result, viewGroup, false);
                return view;
            }

            Map<String, String> item = objects.get(position);

            if (contentView == null) {
                LayoutInflater layoutInflater = (LayoutInflater) getContext()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = layoutInflater.inflate(R.layout.listitem_prolongall_result, viewGroup, false);
            } else {
                view = contentView;
            }

            TextView tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
            TextView tvTitle = (TextView) view.findViewById(R.id.tvTitle);
            TextView tvOld = (TextView) view.findViewById(R.id.tvOld);
            TextView tvNew = (TextView) view.findViewById(R.id.tvNew);
            TextView tvMsg = (TextView) view.findViewById(R.id.tvMsg);

            tvAuthor.setVisibility(item.containsKey(ProlongAllResult.KEY_LINE_AUTHOR) ? View.VISIBLE : View.GONE);
            tvAuthor.setText(item.get(ProlongAllResult.KEY_LINE_AUTHOR));
            tvTitle.setText(item.get(ProlongAllResult.KEY_LINE_TITLE));
            tvOld.setText(item.get(ProlongAllResult.KEY_LINE_OLD_RETURNDATE));
            tvNew.setText(item.get(ProlongAllResult.KEY_LINE_NEW_RETURNDATE));

            tvMsg.setText(item.get(ProlongAllResult.KEY_LINE_MESSAGE));
            return view;
        }

    }

    public class BookingTask extends StepTask<BookingResult> {
        private DetailledItem item;

        public BookingTask(MultiStepResultHelper helper, int useraction, String selection, DetailledItem item) {
            super(helper, useraction, selection);
            this.item = item;
        }

        @Override
        protected BookingResult doInBackground(Void... voids) {
            try {
                return ((EbookServiceApi) app.getApi()).booking(item, app.getAccount(), useraction, selection);
            } catch (IOException e) {
                publishProgress(e, "ioerror");
            } catch (Exception e) {
                ErrorReporter.handleException(e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(BookingResult res) {
            if (getActivity() == null) {
                return;
            }

            if (res == null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage(R.string.error).setCancelable(true).setNegativeButton(R.string.close,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });
                AlertDialog alert = builder.create();
                alert.show();
                return;
            }

            super.onPostExecute(res);
        }
    }

    @Override
    public void onClick(LentItem item, LentAdapter.ViewHolder view) {
        showDetailActivity(item, view);
    }

    @Override
    public void onClick(ReservedItem item, ReservationsAdapter.ViewHolder view) {
        showDetailActivity(item, view);
    }

    private void showDetailActivity(AccountItem item, AccountAdapter.ViewHolder view) {
        Intent intent = new Intent(getContext(), AccountItemDetailActivity.class);
        intent.putExtra(AccountItemDetailActivity.EXTRA_ITEM, item);
        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
                view.itemView, getString(R.string.transition_background));
        ActivityCompat.startActivityForResult(getActivity(), intent, REQUEST_DETAIL, options.toBundle());
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (requestCode == REQUEST_DETAIL && intent != null
                && intent.hasExtra(AccountItemDetailActivity.EXTRA_DATA)) {
            String data = intent.getStringExtra(AccountItemDetailActivity.EXTRA_DATA);
            switch (resultCode) {
            case AccountItemDetailActivity.RESULT_PROLONG:
                prolong(data);
                break;
            case AccountItemDetailActivity.RESULT_DOWNLOAD:
                download(data);
                break;
            case AccountItemDetailActivity.RESULT_CANCEL:
                cancel(data);
                break;
            case AccountItemDetailActivity.RESULT_BOOKING:
                bookingStart(data);
                break;
            }
        }
    }
}