package com.limpoxe.fairy.core.viewfactory;

import android.content.Context;
import android.util.AttributeSet;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2015/12/13.
 *
 * Porting From SupportV7
 */
public class PluginViewInflater {

    final Class<?>[] sConstructorSignature = new Class[] {
            Context.class, AttributeSet.class};

    private final Map<String, Constructor<? extends View>> sConstructorMap = new HashMap<>();

    private final LayoutInflater.Factory mViewfactory;
    private final Context mContext;
    private final Object[] mConstructorArgs = new Object[2];

    public PluginViewInflater(Context context, final LayoutInflater.Factory viewfactory) {
        mContext = context;
        mViewfactory = viewfactory;
    }

    public final View createView(View parent, final String name, Context context,
                                 AttributeSet attrs, boolean inheritContext, boolean themeContext) {
        final Context originalContext = context;

        // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
        // by using the parent's context
        if (inheritContext && parent != null) {
            context = parent.getContext();
        }
        if (themeContext) {
            // We then apply the theme on the context, if specified
            context = themifyContext(context, attrs, true, true);
        }

        // We need to 'inject' our tint aware Views in place of the standard framework versions
        View view = injectView(name, context, attrs);
        if (view != null) {
            return view;
        }

        if (originalContext != context) {
            // If the original context does not equal our themed context, then we need to manually
            // inflate it using the name so that app:theme takes effect.
            return createViewFromTag(context, name, attrs);
        }

        return null;
    }

    private View injectView(String name, Context context, AttributeSet attrs) {
        if (mViewfactory != null) {
            return mViewfactory.onCreateView(name, context, attrs);
        }
        return null;
    };

    private View createViewFromTag(Context context, String name, AttributeSet attrs) {
        if (name.equals("view")) {
            name = attrs.getAttributeValue(null, "class");
        }

        try {
            mConstructorArgs[0] = context;
            mConstructorArgs[1] = attrs;

            if (-1 == name.indexOf('.')) {
                // try the android.widget prefix first...
                return createView(name, "android.widget.");
            } else {
                return createView(name, null);
            }
        } catch (Exception e) {
            // We do not want to catch these, lets return null and let the actual LayoutInflater
            // try
            return null;
        } finally {
            // Don't retain static reference on context.
            mConstructorArgs[0] = null;
            mConstructorArgs[1] = null;
        }
    }

    private View createView(String name, String prefix)
            throws ClassNotFoundException, InflateException {
        Constructor<? extends View> constructor = sConstructorMap.get(name);

        try {
            if (constructor == null) {
                // Class not found in the cache, see if it's real, and try to add it
                Class<? extends View> clazz = getClassLoader(mContext, name, prefix).loadClass(
                        prefix != null ? (prefix + name) : name).asSubclass(View.class);

                constructor = clazz.getConstructor(sConstructorSignature);
                sConstructorMap.put(name, constructor);
            }
            constructor.setAccessible(true);
            return constructor.newInstance(mConstructorArgs);
        } catch (Exception e) {
            // We do not want to catch these, lets return null and let the actual LayoutInflater
            // try
            return null;
        }
    }

    private ClassLoader getClassLoader(Context context, String name, String prefix) {
        return context.getClassLoader();
    }

    /**
     * Allows us to emulate the {@code android:theme} attribute for devices before L.
     */
    public static Context themifyContext(Context context, AttributeSet attrs,
                                         boolean useAndroidTheme, boolean useAppTheme) {
        //wrap it in a new wrapper
        //context = new ContextThemeWrapper(context, themeId);
        return context;
    }

}