package com.flipboard.bottomsheet.commons;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.view.ViewCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import flipboard.bottomsheet.commons.R;

@SuppressLint("ViewConstructor")
public class IntentPickerSheetView extends FrameLayout {

    public interface Filter {
        boolean include(ActivityInfo info);
    }

    public interface OnIntentPickedListener {
        void onIntentPicked(ActivityInfo activityInfo);
    }

    private class SortAlphabetically implements Comparator<ActivityInfo> {
        @Override
        public int compare(ActivityInfo lhs, ActivityInfo rhs) {
            return lhs.label.compareTo(rhs.label);
        }
    }

    private class FilterNone implements Filter {
        @Override
        public boolean include(ActivityInfo info) {
            return true;
        }
    }

    /**
     * Represents an item in the picker grid
     */
    public static class ActivityInfo {
        public final Drawable icon;
        public final String label;
        public final ComponentName componentName;
        public Object tag;

        public ActivityInfo(Drawable icon, String label, Class<?> clazz) {
            this.icon = icon;
            this.label = label;
            this.componentName = new ComponentName(clazz.getPackage().getName(), clazz.getName());
        }

        ActivityInfo(Drawable icon, CharSequence label, ComponentName componentName) {
            this.icon = icon;
            this.label = label.toString();
            this.componentName = componentName;
        }

        public Intent getConcreteIntent(Intent intent) {
            Intent concreteIntent = new Intent(intent);
            concreteIntent.setComponent(componentName);
            return concreteIntent;
        }
    }

    private final Intent intent;
    private final GridView appGrid;
    private final List<ActivityInfo> mixins = new ArrayList<>();

    private Adapter adapter;
    private Filter filter = new FilterNone();
    private Comparator<ActivityInfo> sortMethod = new SortAlphabetically();

    public IntentPickerSheetView(Context context, Intent intent, @StringRes int titleRes, OnIntentPickedListener listener) {
        this(context, intent, context.getString(titleRes), listener);
    }

    public IntentPickerSheetView(Context context, final Intent intent, final String title, final OnIntentPickedListener listener) {
        super(context);
        this.intent = intent;

        inflate(context, R.layout.grid_sheet_view, this);
        appGrid = (GridView) findViewById(R.id.grid);
        TextView titleView = (TextView) findViewById(R.id.title);

        titleView.setText(title);
        appGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                listener.onIntentPicked(adapter.getItem(position));
            }
        });

        ViewCompat.setElevation(this, Util.dp2px(getContext(), 16f));
    }

    public void setSortMethod(Comparator<ActivityInfo> sortMethod) {
        this.sortMethod = sortMethod;
    }

    public void setFilter(Filter filter) {
        this.filter = filter;
    }

    /**
     * Adds custom mixins to the resulting picker sheet
     *
     * @param infos Custom ActivityInfo classes to mix in
     */
    public void setMixins(@NonNull List<ActivityInfo> infos) {
        mixins.clear();
        mixins.addAll(infos);
    }

    public List<ActivityInfo> getMixins() {
        return this.mixins;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        this.adapter = new Adapter(getContext(), intent, mixins);
        appGrid.setAdapter(this.adapter);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        final float density = getResources().getDisplayMetrics().density;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
            appGrid.setNumColumns((int) (getWidth() / (100 * density)));
        } else {
            // On Jelly Bean and below setNumColumns does not redraw the view if we call it during
            // a layout pass. We must post setting the number of columns to avoid this.
            post(new Runnable() {
                @Override
                public void run() {
                    appGrid.setNumColumns((int) (getWidth() / (100 * density)));
                }
            });
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // Necessary for showing elevation on 5.0+
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setOutlineProvider(new Util.ShadowOutline(w, h));
        }
    }

    private class Adapter extends BaseAdapter {

        final List<ActivityInfo> activityInfos;
        final LayoutInflater inflater;

        public Adapter(Context context, Intent intent, List<ActivityInfo> mixins) {
            inflater = LayoutInflater.from(context);
            PackageManager pm = context.getPackageManager();
            List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0);
            activityInfos = new ArrayList<>(infos.size() + mixins.size());
            activityInfos.addAll(mixins);
            for (ResolveInfo info : infos) {
                ComponentName componentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
                ActivityInfo activityInfo = new ActivityInfo(info.loadIcon(pm), info.loadLabel(pm), componentName);
                if (filter.include(activityInfo)) {
                    activityInfos.add(activityInfo);
                }
            }
            Collections.sort(activityInfos, sortMethod);
        }

        @Override
        public int getCount() {
            return activityInfos.size();
        }

        @Override
        public ActivityInfo getItem(int position) {
            return activityInfos.get(position);
        }

        @Override
        public long getItemId(int position) {
            return activityInfos.get(position).componentName.hashCode();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.sheet_grid_item, parent, false);
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            ActivityInfo info = activityInfos.get(position);
            holder.icon.setImageDrawable(info.icon);
            holder.label.setText(info.label);

            return convertView;
        }

        class ViewHolder {
            final ImageView icon;
            final TextView label;

            ViewHolder(View root) {
                icon = (ImageView) root.findViewById(R.id.icon);
                label = (TextView) root.findViewById(R.id.label);
            }
        }

    }

}
@@ -4547,132 +4547,119 @@
 d on
-Layout(boolean changed, int left, int top
+Measure(int widthMeasureSpec
 , int 
-r
+he
 ight
-, int bottom) %7B%0A        super.onLayout(changed, left, top, right, bottom
+MeasureSpec) %7B%0A        int width = MeasureSpec.getSize(widthMeasureSpec
 );%0A 
@@ -4735,86 +4735,8 @@
 ty;%0A
-        if (Build.VERSION.SDK_INT %3E Build.VERSION_CODES.JELLY_BEAN_MR1) %7B%0A    
     
@@ -4764,34 +4764,29 @@
 umns((int) (
-getW
+w
 idth
-()
  / (100 * de
@@ -4807,424 +4807,61 @@
     
-%7D else %7B%0A            // On Jelly Bean and below setNumColumns does not redraw the view if we call it during%0A            // a layout pass. We must post setting the number of columns to avoid this.%0A            post(new Runnable() %7B%0A                @Override%0A                public void run() %7B%0A                    appGrid.setNumColumns((int) (getWidth() / (100 * density)));%0A                %7D%0A            %7D);%0A        %7D
+super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 %0A   

Handle column number in onMeasure instead of onLayout