package com.billy.android.swipe;

import android.app.Activity;
import android.content.Context;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;

/**
 * A smart swipe util to wrap a view and consume swipe event to do some business via {@link SwipeConsumer}
 * classic usage:
 * <pre>
 *     SmartSwipe.wrap(view)    //specific the view to wrap
 *          .addConsumer(new StretchConsumer()) // add consumer to consume swipe event
 *          .enableVertical(); //enable consumer`s direction(s)
 * </pre>
 * @author billy.qi
 */
public class SmartSwipe {

    /**
     * wrap an activity
     * the content view is: android.R.id.content
     * @param activity activity
     * @return the wrapper
     */
    public static SmartSwipeWrapper wrap(Activity activity) {
        SmartSwipeWrapper wrapper = peekWrapperFor(activity);
        if (wrapper != null) {
            return wrapper;
        }
        View decorView = activity.getWindow().getDecorView();
        if (decorView instanceof ViewGroup) {
            ViewGroup group = (ViewGroup) decorView;
            int childCount = group.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = group.getChildAt(i);
                if (child.findViewById(android.R.id.content) != null) {
                    return wrap(child);
                }
            }
        }
        View contentView = decorView.findViewById(android.R.id.content);
        return wrap(contentView);
    }

    /**
     * peek wrapper for the specific activity, return the origin {@link SmartSwipeWrapper} if exists, else return null
     * @param activity activity
     * @return the wrapper if exists, otherwise returns null
     */
    public static SmartSwipeWrapper peekWrapperFor(Activity activity) {
        View decorView = activity.getWindow().getDecorView();
        View contentView = decorView.findViewById(android.R.id.content);
        while (contentView != null && contentView != decorView) {
            if (contentView.getParent() instanceof SmartSwipeWrapper) {
                return (SmartSwipeWrapper) contentView.getParent();
            }
            contentView = (View) contentView.getParent();
        }
        return null;
    }

    /**
     * wrap a view in activity, view id is specified
     * if already wrapped, returns the original wrapper
     * @param activity activity
     * @param viewId the id of view to be wrapped
     * @return the original wrapper or create a new wrapper to wrap the view and replace its place into parent
     */
    public static SmartSwipeWrapper wrap(Activity activity, int viewId) {
        if (activity != null) {
            View view = activity.findViewById(viewId);
            if (view != null) {
                return wrap(view);
            }
        }
        return null;
    }

    /**
     * wrap a view
     * @param view the view to be wrapped
     * @return the original wrapper or create a new wrapper to wrap the view and replace its place into parent
     */
    public static SmartSwipeWrapper wrap(View view) {
        SmartSwipeWrapper wrapper = peekWrapperFor(view);
        if (wrapper != null) {
            return wrapper;
        }
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        if (view.getParent() != null) {
            ViewGroup viewParent = (ViewGroup) view.getParent();
            wrapper = createNewWrapper(view.getContext());
            int index = viewParent.indexOfChild(view);
            viewParent.removeView(view);
            viewParent.addView(wrapper, index, layoutParams);
        } else {
            wrapper = createNewWrapper(view.getContext());
            if (layoutParams != null) {
                wrapper.setLayoutParams(layoutParams);
            }
        }
        wrapper.setContentView(view);
        return wrapper;
    }

    /**
     * get wrapper of the specific view
     * @param view view to find wrapper
     * @return the original wrapper of the specific view
     */
    public static SmartSwipeWrapper peekWrapperFor(View view) {
        if (view.getParent() instanceof SmartSwipeWrapper) {
            return (SmartSwipeWrapper) view.getParent();
        }
        return null;
    }

    /**
     * switch direction enable for all {@link SwipeConsumer} that already added to the wrapper
     * @param view the view which be wrapped
     * @param enable true: to enable, false: to disable
     * @param direction direction to enable or disable
     */
    public static void switchDirectionEnable(View view, boolean enable, int direction) {
        enableOrDisableFor(peekWrapperFor(view), enable, direction);
    }

    public static void switchDirectionEnable(Activity activity, boolean enable, int direction) {
        enableOrDisableFor(peekWrapperFor(activity), enable, direction);
    }

    private static void enableOrDisableFor(SmartSwipeWrapper wrapper, boolean enable, int direction) {
        if (wrapper != null) {
            wrapper.enableDirection(direction, enable);
        }
    }

    public static int dp2px(int dp, Context context){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
    }

    public static int ensureBetween(int origin, int min, int max) {
        return Math.max(min, Math.min(origin, max));
    }

    public static float ensureBetween(float origin, float min, float max) {
        return Math.max(min, Math.min(origin, max));
    }

    public static double ensureBetween(double origin, double min, double max) {
        return Math.max(min, Math.min(origin, max));
    }


    private static IWrapperFactory factory;

    private static SmartSwipeWrapper createNewWrapper(Context context) {
        final IWrapperFactory factory = SmartSwipe.factory;
        if (factory != null) {
            SmartSwipeWrapper wrapper = factory.createWrapper(context);
            if (wrapper != null) {
                return wrapper;
            }
        }
        return new SmartSwipeWrapper(context);
    }

    /**
     * set the factory of {@link SmartSwipeWrapper}
     * by default, create the {@link SmartSwipeWrapper} instance to wrap if {@link #factory} is null
     * @param factory the factory
     * @see #createNewWrapper(Context)
     */
    public static void setFactory(IWrapperFactory factory) {
        SmartSwipe.factory = factory;
    }

    public interface IWrapperFactory {
        SmartSwipeWrapper createWrapper(Context context);
    }

    static {
        //set wrapper factory automatically
        try {
            //android x
            boolean success = initFactoryByClassName("com.billy.android.swipe.androidx.WrapperFactory");
            if (!success) {
                //android support
                initFactoryByClassName( "com.billy.android.swipe.support.WrapperFactory");
            }
        } catch(Throwable e) {
            e.printStackTrace();
        }
    }

    private static boolean initFactoryByClassName(String factoryClassName)  {
        Class<?> clazz;
        try {
            clazz = Class.forName(factoryClassName);
            if (clazz != null) {
                Object o = clazz.getConstructor().newInstance();
                if (o instanceof IWrapperFactory) {
                    setFactory((IWrapperFactory) o);
                }
            }
            return true;
        } catch(Exception ignored) {
        }
        return false;
    }
}