package net.xpece.material.navigationdrawer.list;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;

import net.xpece.material.navigationdrawer.BuildConfig;
import net.xpece.material.navigationdrawer.R;
import net.xpece.material.navigationdrawer.descriptors.CompositeNavigationItemDescriptor;
import net.xpece.material.navigationdrawer.descriptors.GraphicNavigationItemDescriptor;
import net.xpece.material.navigationdrawer.descriptors.NavigationItemDescriptor;
import net.xpece.material.navigationdrawer.descriptors.NavigationSectionDescriptor;
import net.xpece.material.navigationdrawer.internal.Utils;

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

/**
 * Created by pechanecjr on 14. 12. 2014.
 */
abstract class CompactNavigationListFragmentDelegate implements
    AdapterView.OnItemClickListener, CompactNavigationListFragmentImpl {
    public static final String TAG = CompactNavigationListFragmentDelegate.class.getSimpleName();

    private static final NavigationListFragmentCallbacks DUMMY_CALLBACKS = new NavigationListFragmentCallbacks() {
        @Override
        public void onNavigationItemSelected(View view, int position, int id, NavigationItemDescriptor item) {
            //
        }
    };
    private NavigationListFragmentCallbacks mCallbacks = DUMMY_CALLBACKS;

    private ListView mListView;

    private CompactNavigationListAdapter mAdapter;
    private boolean mReselectEnabled = true;
    private int mLastSelected = -1;

    private List<NavigationSectionDescriptor> mSections = new ArrayList<>(0);

    private View mHeader = null;
    private int mTheme;

    private LayoutInflater mInflater;

    public CompactNavigationListFragmentDelegate() {
    }

    public abstract Activity getActivity();

    public abstract View getView();

    @Override
    public void onAttach(Activity activity) {
        mCallbacks = (NavigationListFragmentCallbacks) activity;
    }

    @Override
    public void onDetach() {
        mCallbacks = DUMMY_CALLBACKS;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt("mLastSelected", mLastSelected);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (mTheme > 0) {
            Context newContext = new ContextThemeWrapper(inflater.getContext(), mTheme);
            inflater = inflater.cloneInContext(newContext);
        }
        mInflater = inflater;

        View view = inflater.inflate(R.layout.mnd_list_compact, container, false);
        mListView = (ListView) view.findViewById(R.id.mnd_list_compact);
        return view;
    }

    @Override
    public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        mListView.setOnItemClickListener(this);
        mListView.setSelector(Utils.getSelectorDrawable(view.getContext()));

        if (savedInstanceState != null) {
            mLastSelected = savedInstanceState.getInt("mLastSelected");
        }
    }

    @Override
    public void onDestroyView() {
        mInflater = null;

        mListView = null;
    }

    @Override
    public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
        TypedArray a = activity.obtainStyledAttributes(attrs, R.styleable.NavigationListFragment);
        mTheme = a.getResourceId(R.styleable.NavigationListFragment_android_theme, 0);
        a.recycle();
    }

    @Override
    public LayoutInflater getLayoutInflater2() {
        return mInflater;
    }

    @Override
    public void setItems(List<? extends CompositeNavigationItemDescriptor> items) {
        NavigationSectionDescriptor section = new NavigationSectionDescriptor().addItems(items);
        List<NavigationSectionDescriptor> sections = new ArrayList<>(1);
        sections.add(section);
        setSections(sections);
    }

    /**
     * Set all sections that would be shown in the navigation list except optional pinned section.
     *
     * @param sections
     */
    @Override
    public void setSections(List<NavigationSectionDescriptor> sections) {
        mSections = sections;
        updateSections();
    }

    private void updateSections() {
        if (getView() == null) return;

        mAdapter = new CompactNavigationListAdapter(mSections);
        mAdapter.setReselectEnabled(mReselectEnabled);
        mAdapter.setActivatedItem(mLastSelected);
        mListView.setAdapter(mAdapter);
    }

    /**
     * Use this method to set a header view. This header is selectable by default so you can use it as
     * a no-op close drawer button. Alternatively you would set up an {@link android.view.View.OnClickListener}
     * beforehand. <em>The header view is not managed by this class, it's completely in your hands.</em>
     *
     * @param view
     */
    @Override
    public void setHeaderView(View view, boolean clickable) {
        if (view == mHeader) return;
        if (mHeader != null) {
            mListView.removeHeaderView(mHeader);
        }
        if (view != null) {
            if (mListView != null) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                    if (mListView.getAdapter() != null) mListView.setAdapter(null);
                    mListView.addHeaderView(view, null, clickable);
                    if (mAdapter != null) mListView.setAdapter(mAdapter);
                } else {
                    mListView.addHeaderView(view, null, clickable);
                }
            }
        }
        mHeader = view;
    }

    /**
     * Call this method when the source data set has changed, e.g. when you changed badges.
     */
    @Override
    public void notifyDataSetChanged() {
        if (mAdapter != null) {
            mAdapter.notifyDataSetChanged();
        }
    }

    /**
     * Use this to set a color as the navigation list background.
     * Remember not to use translucent or transparent colors (pinned section has to have an opaque background).
     *
     * @param color
     */
    @Override
    public void setBackgroundColor(int color) {
        if (getView() != null) {
            getView().setBackgroundColor(color);
        }
    }

    /**
     * Use this to set a drawable as the navigation list background.
     * Remember not to use vertical gradients (pinned section has to have an opaque background).
     *
     * @param drawable
     */
    @Override
    public void setBackground(Drawable drawable) {
        if (getView() != null) {
            Utils.setBackground(getView(), drawable);
        }
    }

    /**
     * Use this to resolve a drawable or color resource ID as a drawable and set it as the navigation list background.
     * Remember not to use vertical gradients (pinned section has to have an opaque background).
     *
     * @param resource
     */
    @Override
    public void setBackgroundResource(@DrawableRes @ColorRes int resource) {
        if (getView() != null) {
            getView().setBackgroundResource(resource);
        }
    }

    /**
     * Use this to resolve an attribute as a drawable and set it as the navigation list background.
     * Remember not to use vertical gradients (pinned section has to have an opaque background).
     *
     * @param attr
     */
    @Override
    public void setBackgroundAttr(@AttrRes int attr) {
        if (getView() != null) {
            Drawable d = Utils.getDrawableAttr(getView().getContext(), attr);
            setBackground(d);
        }
    }

    /**
     * Use this method for marking selected item from outside. Typically you call this in
     * {@link android.app.Activity#onPostCreate(android.os.Bundle)} after you determine which
     * section was selected previously or by default.
     *
     * @param id
     */
    @Override
    public void setSelectedItem(int id) {
        if (mAdapter != null) {

            int position = mAdapter.getPositionById(id);
            trySelectPosition(position);

        } else {
            throw new IllegalStateException("No adapter yet!");
        }
    }

    private void trySelectPosition(final int itemPosition) {
        final int listPosition = itemPosition + mListView.getHeaderViewsCount();
//    if (listPosition == mLastSelected) return;
        if (itemPosition < 0) {
            mListView.setItemChecked(listPosition, false);
            mAdapter.setActivatedItem(-1);
            mLastSelected = -1;
            return;
        }
        CompositeNavigationItemDescriptor item = (CompositeNavigationItemDescriptor) mAdapter.getItem(itemPosition);
        if (item != null && item.isSticky()) {
            mListView.setItemChecked(mLastSelected, false);
            mListView.setItemChecked(listPosition, true);
            mAdapter.setActivatedItem(itemPosition);
            mLastSelected = listPosition;
        } else {
            selectPreviousPosition(listPosition);
        }
    }

    private void selectPreviousPosition(int deselect) {
        mListView.setItemChecked(deselect, false);
        mListView.setItemChecked(mLastSelected, true);
    }

    /**
     * @param parent
     * @param view
     * @param position
     * @param id
     */
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        GraphicNavigationItemDescriptor item = (GraphicNavigationItemDescriptor) parent.getItemAtPosition(position);
        onItemClick(view, position, item != null ? item.getId() : (int) id, item);
    }

    private void onItemClick(View view, int position, int id, GraphicNavigationItemDescriptor item) {
        // header views and items from pinned section are not sticky, don't even try
        if (position >= 0 && position < mListView.getHeaderViewsCount()) {
//        || position > mListView.getHeaderViewsCount() + mAdapter.getCount()) {
            selectPreviousPosition(position);
        } else {
            final int itemPosition = position - mListView.getHeaderViewsCount();
            trySelectPosition(itemPosition);
        }

        mCallbacks.onNavigationItemSelected(view, position, id, item);
    }

    public void setReselectEnabled(boolean reselectEnabled) {
        mReselectEnabled = reselectEnabled;
        if (mAdapter != null) {
            mAdapter.setReselectEnabled(reselectEnabled);
        }
    }

    private static void timber(String s) {
        if (BuildConfig.DEBUG) Log.d(TAG, s);
    }
}