/*
 * Copyright 2016 J. Alexandre Oliveira
 *
 * 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.alexive.graphicalutils.lists;

import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.alexive.graphicalutils.R;
import com.alexive.graphicalutils.view.ProportionalImageView;
import com.alexive.graphicalutils.view.ViewUtils;

/**
 * Base grid adapter class. Provides subheaders, click listeners setting, etc.
 */
public abstract class GridAdapter extends ListAdapter {
    /*
    ---------------------
    * ---------------------
    * TODO MAJOR REFACTOR!!!!!!! or just make it an hybrid (rows with n columns or w/ 1)
    * ---------------------
    * ---------------------
     */

    private final DetailsType mDetailsViewType;
    private final String DETAILS_VIEW_TAG = "detailsviewtag";
    private GridItemSpecs gridSpecs;
    private int numCols;

    public GridAdapter(DetailsType type) {
        super();
        mDetailsViewType = type;
    }

    @Override
    public AwesomeViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        if (i == ListItemType.GRID_ITEM.resId) {
            return getItemView(viewGroup);
        } else
            return super.onCreateViewHolder(viewGroup, i);
    }

    protected AwesomeViewHolder getItemView(ViewGroup group) {
        if (gridSpecs == null)
            gridSpecs = new GridItemSpecs();
        LayoutInflater inflater = LayoutInflater.from(group.getContext());
        View base = inflater.inflate(gridSpecs.detailsViewFloats ? R.layout
                .grid_float_headerfooter_tile : R.layout.grid_dummy_tile, group, false);
        base.setClickable(true);
        AwesomeViewHolder result = new AwesomeViewHolder(base);
        setListenerForHolder(result);

        ProportionalImageView imageView = (ProportionalImageView) base.findViewById(R.id.imageView);
        if (gridSpecs.forceSquareImage)
            imageView.setSquare();
        result.setImageView1(imageView);
        if (mDetailsViewType == DetailsType.NONE) {
            return result;
        }
        View details = getDetailsView(inflater, group, result);

        ImageButton imageButton = (ImageButton) details.findViewById(R.id.imageButton);
        imageButton.setOnClickListener(new ButtonListener(result));
        result.setButton(imageButton);

        if (gridSpecs.detailsViewFloats) {
            //We just add it to the framelayout and set the gravity
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams
                    .FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            FrameLayout fl = (FrameLayout) base.findViewById(R.id.floatParent);
            params.gravity = gridSpecs.detailsGravityIsTop ? Gravity.TOP : Gravity.BOTTOM;
            fl.addView(details, 1, params);
        } else {
            LinearLayout parent = (LinearLayout) base.findViewById(R.id.noFloatParent);
//            LinearLayout parent = (LinearLayout) base.findViewById(gridSpecs.detailsGravityIsTop ? R
//                    .id.headerNoFloat : R.id.footerNoFloat);
//            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams
//                    .FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            parent.addView(details, gridSpecs.detailsGravityIsTop ? 0 : 1);
            base.findViewById(R.id.noFloatParent).requestLayout();
        }

        return result;
    }

//    public String getGridImageTransitionName(Context c) {
//        return c.getString(R.string.image_transition_name);
//    }

    public View getDetailsView(LayoutInflater inflater, ViewGroup parent,
                               AwesomeViewHolder result) {
        //TODO FORCE DARK MODE
        View view = null;
        switch (mDetailsViewType) {
            case SINGLE_LINE:
                view = inflater.inflate(R.layout.griddetails_single_line, null);
                break;
            case TWO_LINES:
                view = inflater.inflate(R.layout.griddetails_two_lines, null);
                break;
            default:
            case NONE:
                return null;
        }
        view.setTag(DETAILS_VIEW_TAG);
        result.setDetailsView(view);
        result.setText1((TextView) view.findViewById(android.R.id.text1));
        result.setText2((TextView) view.findViewById(android.R.id.text2));
        result.setButton((ImageButton) view.findViewById(R.id.imageButton));
        return view;
    }

    @Override
    public boolean shouldSubHeaderTextColorBeAccent() {
        return false;
    }

    @Override
    public boolean drawDivider(int i) {
        //Dividers in a grid make no sense.
        return false;
    }

    @Override
    public void bindDataToListItem(int index,
                                   View itemView,
                                   ImageView iconOrAvatar,
                                   ImageButton button,
                                   TextView... texts) {
        //useless
        //you should override bindDataToItem
    }

    @Override
    protected void preBindData(int i, AwesomeViewHolder awesomeViewHolder) {
        bindDataToItem(i,
                awesomeViewHolder.itemView,
                awesomeViewHolder.getDetailsView(),
                awesomeViewHolder.getImageView1(),
                awesomeViewHolder.button,
                awesomeViewHolder.text1,
                awesomeViewHolder.text2);
    }

    /**
     * Fills in the list item
     *
     * @param index        The index of the item
     * @param itemView     The list item's view
     * @param detailsView  Item's detail view, typically under the image
     * @param imageViewOrAvatar    The item's ImageView, or the avatar if it's an ordinary item
     * @param imageButton  If it's an ordinary list item, it's button
     * @param txt          The item's text views, from top to bottom, left to right
     */
    public abstract void bindDataToItem(int index,
                                        View itemView,
                                        View detailsView,
                                        ImageView imageViewOrAvatar,
                                        ImageButton imageButton,
                                        TextView... txt);


    public void setItemSpecs(GridItemSpecs specs) {
        gridSpecs = specs;
    }

    //public abstract void bindDataToItemView(int position, ImageView imageView, View... detailsView);

    public GridLayoutManager getGridLayoutManager(Context ctx, int numColumns) {
        this.numCols = numColumns;
        GridLayoutManager mngr = new GridLayoutManager(ctx, numColumns);
        mngr.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                return getItemViewType(position) == ListItemType.GRID_ITEM.resId ? 1 : numCols;
            }
        });
        return mngr;
    }

    public RecyclerView.ItemDecoration getDecorationForSmallSpacing(Context c) {
        return new Decorator(ViewUtils.convertDPtoPixels(c, 1));
    }

    public RecyclerView.ItemDecoration getDecorationForLargeSpacing(Context c) {
        return new Decorator(ViewUtils.convertDPtoPixels(c, 4));
    }

    public enum DetailsType {
        NONE,
        SINGLE_LINE,
        TWO_LINES
    }

    public static class GridItemSpecs {
        public boolean detailsGravityIsTop = false;
        public boolean detailsViewFloats = false;
        public boolean forceDarkMode = false;
        public boolean forceSquareImage = true;
    }

    private class Decorator extends RecyclerView.ItemDecoration {

        private final int padding;

        public Decorator(int padding) {
            this.padding = padding;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            int pos = parent.getChildAdapterPosition(view);
            if (getListItemDataType(pos) == ListItemType.SUB_HEADER)
                return;
            //TODO Faster approach
            //TODO actually compute the list item's padding IF it's on the edge.
            //Having subheaders/items taking up a full row made the code I had before messed up
//      //If the list has subheaders, without this the padding will be VERY EFFED Up.
//      int newPos = 0;
//      for (int i = 0; i <= pos; i++) {
//        if (isSubHeader(i)) {
//         newPos = 0;
//        }else
//          newPos++;
//      }
//
//      if(newPos % numCols != 0)
            outRect.left = padding;
//      if ((newPos + 1) % numCols != 0);
            outRect.right = padding;
            outRect.bottom = padding;
            outRect.top = padding;
        }
    }
}