package com.eowise.recyclerview.stickyheaders;

import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerViewHelper;
import android.view.View;
import android.view.ViewGroup;

import java.util.HashMap;
import java.util.Iterator;

/**
 * Created by aurel on 22/09/14.
 */
public class StickyHeadersItemDecoration extends RecyclerView.ItemDecoration {

    private final static int NO_HEIGHT = -1;

    private final StickyHeadersAdapter adapter;
    private final RecyclerView parent;
    private final RecyclerView.ViewHolder headerViewHolder;
    private final HashMap<Long, Boolean> headers;
    private final AdapterDataObserver adapterDataObserver;
    private boolean overlay;
    private int headerHeight;

    public StickyHeadersItemDecoration(StickyHeadersAdapter adapter, RecyclerView parent) {
        this(adapter, parent, false);
    }

    public StickyHeadersItemDecoration(StickyHeadersAdapter adapter, RecyclerView parent, boolean overlay) {
        this.adapter = adapter;
        this.parent = parent;
        this.headerViewHolder = adapter.onCreateViewHolder(parent);
        this.overlay = overlay;
        this.headers = new HashMap<Long, Boolean>();
        this.adapterDataObserver = new AdapterDataObserver();
        this.headerHeight = NO_HEIGHT;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {


        final int childCount = parent.getChildCount();
        final RecyclerView.LayoutManager lm = parent.getLayoutManager();
        View header = headerViewHolder.itemView;
        Float lastY = null;

        for (int i = childCount - 1; i >= 0; i--) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)child.getLayoutParams();
            final int position = parent.getChildPosition(child);
            RecyclerView.ViewHolder holder = parent.getChildViewHolder(child);

            if (!lp.isItemRemoved()) {

                float translationY = ViewCompat.getTranslationY(child);

                if (i == 0 || isHeader(holder)) {

                    float y = getHeaderY(child, lm) + translationY;

                    if (lastY != null && lastY < y + headerHeight) {
                        y = lastY - headerHeight;
                    }

                    adapter.onBindViewHolder(headerViewHolder, position);

                    c.save();
                    c.translate(0, y);
                    header.draw(c);
                    c.restore();

                    lastY = y;
                }
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

        ensureHeaderLaidOut();

        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)view.getLayoutParams();
        RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);

        if (overlay || !isHeader(holder)) {
            outRect.set(0, 0, 0, 0);
        }
        else {
            //TODO: Handle layout direction
            outRect.set(0, headerHeight, 0, 0);
        }

        if (lp.isItemRemoved()) {
            headers.remove(holder.getItemId());
        }
    }

    public void registerAdapterDataObserver(RecyclerView.Adapter adapter) {
        adapter.registerAdapterDataObserver(adapterDataObserver);
    }

    private float getHeaderY(View item, RecyclerView.LayoutManager lm) {
        return  lm.getDecoratedTop(item) < 0 ? 0 : lm.getDecoratedTop(item);
    }

    private Boolean isHeader(RecyclerView.ViewHolder holder) {
        if (!headers.containsKey(holder.getItemId())  || headers.get(holder.getItemId()) == null) {
            int itemPosition = RecyclerViewHelper.convertPreLayoutPositionToPostLayout(parent, holder.getPosition());

            if (itemPosition == 0) {
                headers.put(holder.getItemId(), true);
            }
            else {
                headers.put(holder.getItemId(), adapter.getHeaderId(itemPosition) != adapter.getHeaderId(itemPosition -1));
            }
        }

        return headers.get(holder.getItemId());
    }


    private void ensureHeaderLaidOut() {
        if (headerHeight == NO_HEIGHT) {
            int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
            int heightSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.AT_MOST);
            headerViewHolder.itemView.measure(widthSpec, heightSpec);
            headerViewHolder.itemView.layout(0, 0, headerViewHolder.itemView.getMeasuredWidth(), headerViewHolder.itemView.getMeasuredHeight());
            headerHeight = headerViewHolder.itemView.getMeasuredHeight();
        }
    }


    private class AdapterDataObserver extends RecyclerView.AdapterDataObserver {

        public AdapterDataObserver() {
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            RecyclerView.ViewHolder holder = parent.findViewHolderForPosition(positionStart + 1);
            if (holder != null) {
                headers.put(holder.getItemId(), null);
            }
            else {
                cleanOffScreenItemsIds();
            }
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            RecyclerView.ViewHolder holder = parent.findViewHolderForPosition(positionStart);
            if (holder != null) {
                headers.put(holder.getItemId(), null);
            }
            else {
                cleanOffScreenItemsIds();
            }
        }

        private void cleanOffScreenItemsIds() {
            Iterator<Long> iterator = headers.keySet().iterator();
            while (iterator.hasNext()) {
                long itemId = iterator.next();
                if (parent.findViewHolderForItemId(itemId) == null) {
                    iterator.remove();
                }
            }
        }
    }

}

@@ -4536,43 +4536,9 @@
 pec(
-ViewGroup.LayoutParams.WRAP_CONTENT
+0
 , Vi
@@ -4556,15 +4556,19 @@
 pec.
-AT_MOST
+UNSPECIFIED
 );%0A 

fix measure in 4.2.2