package org.fdroid.fdroid.views.fragments;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.compat.ArrayAdapterCompat;
import org.fdroid.fdroid.compat.CursorAdapterCompat;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.views.AppListAdapter;
import org.fdroid.fdroid.views.AvailableAppListAdapter;

import java.util.ArrayList;
import java.util.List;

public class AvailableAppsFragment extends AppListFragment implements
        LoaderManager.LoaderCallbacks<Cursor> {

    private static final String TAG = "AvailableAppsFragment";

    private static final String PREFERENCES_FILE = "CategorySpinnerPosition";
    private static final String CATEGORY_KEY = "Selection";
    private static String defaultCategory;

    private List<String> categories;

    @Nullable
    private View categoryWrapper;

    @Nullable
    private Spinner categorySpinner;
    private String currentCategory;
    private AppListAdapter adapter;

    @Override
    protected String getFromTitle() {
        return getString(R.string.tab_available_apps);
    }

    @Override
    protected AppListAdapter getAppListAdapter() {
        if (adapter == null) {
            final AppListAdapter a = AvailableAppListAdapter.create(getActivity(), null, CursorAdapterCompat.FLAG_AUTO_REQUERY);
            Preferences.get().registerUpdateHistoryListener(new Preferences.ChangeListener() {
                @Override
                public void onPreferenceChange() {
                    a.notifyDataSetChanged();
                }
            });
            adapter = a;
        }
        return adapter;
    }

    private class CategoryObserver extends ContentObserver {

        private final ArrayAdapter<String> adapter;

        CategoryObserver(ArrayAdapter<String> adapter) {
            // Using Looper.getMainLooper() ensures that the onChange method is run on the main thread.
            super(new Handler(Looper.getMainLooper()));
            this.adapter = adapter;
        }

        @Override
        public void onChange(boolean selfChange) {
            final Activity activity = getActivity();
            if (!isAdded() || adapter == null || activity == null) {
                return;
            }

            // Because onChange is always invoked on the main thread (see constructor), we want to
            // run the database query on a background thread. Afterwards, the UI is updated
            // on a foreground thread.
            new AsyncTask<Void, Void, List<String>>() {
                @Override
                protected List<String> doInBackground(Void... params) {
                    return AppProvider.Helper.categories(activity);
                }

                @Override
                protected void onPostExecute(List<String> loadedCategories) {
                    adapter.clear();
                    categories = loadedCategories;
                    ArrayAdapterCompat.addAll(adapter, translateCategories(activity, loadedCategories));
                }
            }.execute();
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            onChange(selfChange);
        }
    }

    /**
     * Attempt to translate category names with fallback to default name if no translation available
     */
    private static List<String> translateCategories(Context context, List<String> categories) {
        List<String> translatedCategories = new ArrayList<>(categories.size());
        Resources res = context.getResources();
        String pkgName = context.getPackageName();
        for (String category : categories) {
            String resId = category.replace(" & ", "_").replace(" ", "_").replace("'", "");
            int id = res.getIdentifier("category_" + resId, "string", pkgName);
            translatedCategories.add(id == 0 ? category : context.getString(id));
        }
        return translatedCategories;
    }

    private Spinner setupCategorySpinner(Spinner spinner) {

        categorySpinner = spinner;
        categorySpinner.setId(R.id.category_spinner);

        categories = AppProvider.Helper.categories(getActivity());

        ArrayAdapter<String> adapter = new ArrayAdapter<>(
                getActivity(), android.R.layout.simple_spinner_item, translateCategories(getActivity(), categories));
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        categorySpinner.setAdapter(adapter);

        getActivity().getContentResolver().registerContentObserver(
                AppProvider.getContentUri(), false, new CategoryObserver(adapter));

        categorySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                getListView().setSelection(0);
                setCurrentCategory(categories.get(pos));
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                setCurrentCategory(null);
            }
        });
        return categorySpinner;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.available_app_list, container, false);

        categoryWrapper = view.findViewById(R.id.category_wrapper);
        setupCategorySpinner((Spinner) view.findViewById(R.id.category_spinner));
        defaultCategory = AppProvider.Helper.getCategoryWhatsNew(getActivity());

        return view;
    }

    @Override
    protected Uri getDataUri() {
        if (currentCategory == null || currentCategory.equals(AppProvider.Helper.getCategoryAll(getActivity()))) {
            return AppProvider.getContentUri();
        }
        if (currentCategory.equals(AppProvider.Helper.getCategoryRecentlyUpdated(getActivity()))) {
            return AppProvider.getRecentlyUpdatedUri();
        }
        if (currentCategory.equals(AppProvider.Helper.getCategoryWhatsNew(getActivity()))) {
            return AppProvider.getNewlyAddedUri();
        }
        return AppProvider.getCategoryUri(currentCategory);
    }

    @Override
    protected Uri getDataUri(String query) {
        return AppProvider.getSearchUri(query);
    }

    @Override
    protected int getEmptyMessage() {
        return R.string.empty_available_app_list;
    }

    @Override
    protected int getNoSearchResultsMessage() {
        return R.string.empty_search_available_app_list;
    }

    private void setCurrentCategory(String category) {
        currentCategory = category;
        Utils.debugLog(TAG, "Category '" + currentCategory + "' selected.");
        getLoaderManager().restartLoader(0, null, this);
    }

    @Override
    public void onResume() {
        /* restore the saved Category Spinner position */
        Activity activity = getActivity();
        SharedPreferences p = activity.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
        currentCategory = p.getString(CATEGORY_KEY, defaultCategory);

        if (categorySpinner != null) {
            for (int i = 0; i < categorySpinner.getCount(); i++) {
                if (currentCategory.equals(categorySpinner.getItemAtPosition(i).toString())) {
                    categorySpinner.setSelection(i);
                    break;
                }
            }
        }

        setCurrentCategory(currentCategory);
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        /* store the Category Spinner position for when we come back */
        SharedPreferences p = getActivity().getSharedPreferences(PREFERENCES_FILE,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor e = p.edit();
        e.putString(CATEGORY_KEY, currentCategory);
        e.apply();
    }

    @Override
    protected void onSearch() {
        if (categoryWrapper != null) {
            categoryWrapper.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onSearchStopped() {
        if (categoryWrapper != null) {
            categoryWrapper.setVisibility(View.VISIBLE);
        }
    }
}
