package com.asha.nightowllib.inflater;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by hzqiujiadi on 15/11/7.
 * hzqiujiadi [email protected]
 */
public class InjectedInflaterV11 extends InjectedInflaterBase {

    private static final String TAG = "InjectedInflaterV11";
    private static Method sSetPrivateFactoryMethod;
    private static Field sPrivateFactoryField;

    static {
        try {
            sSetPrivateFactoryMethod = LayoutInflater.class.getDeclaredMethod("setPrivateFactory",Factory2.class);
            sSetPrivateFactoryMethod.setAccessible(true);
            sPrivateFactoryField = LayoutInflater.class.getDeclaredField("mPrivateFactory");
            sPrivateFactoryField.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    protected InjectedInflaterV11(LayoutInflater original, Context newContext) {
        super(original, newContext);
        installPrivateFactory();
    }

    private void installPrivateFactory(){
        try {
            Factory2 originPrivateFactory = (Factory2) sPrivateFactoryField.get(this);
            installPrivateFactory(originPrivateFactory);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void installPrivateFactory(Factory2 originPrivateFactory){
        try {
            // check origin private Factory is not null.
            if ( originPrivateFactory == null ) return;
            // already set
            if ( originPrivateFactory instanceof PrivateFactoryWrapperImpl ) return;
            // wrap PrivateFactory
            Factory2 privateFactory = PrivateFactoryWrapperImpl.wrap(originPrivateFactory, this);
            // replace it.
            sPrivateFactoryField.set(this, privateFactory);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setFactory(Factory factory) {
        if ( factory == null ) return;
        if ( getFactory() == null ){
            super.setFactory(FactoryWrapperImpl.wrap(factory));
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public void setFactory2(Factory2 factory) {
        if ( factory == null ) return;
        if ( getFactory2() == null ){
            super.setFactory(Factory2WrapperImpl.wrap(factory));
        }
    }

    public void setPrivateFactory(Factory2 factory2){
        Log.e(TAG, "warning=== setPrivateFactory");
        try {
            Factory2 privateFactory = (Factory2) sPrivateFactoryField.get(this);
            if ( privateFactory != null
                    &&  privateFactory instanceof PrivateFactoryWrapperImpl ){
                // if it is FactoryWrapper.PrivateFactoryWrapperImpl
                // get inner factory and
                // set to super class
                privateFactory = ((PrivateFactoryWrapperImpl) privateFactory)
                        .getCoreFactory();
                sPrivateFactoryField.set(this, privateFactory);
            }
            // super.setPrivateFactory
            sSetPrivateFactoryMethod.invoke(this, factory2);
            installPrivateFactory(factory2);

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    /********************************************************************************
     *
     * FactoryWrapperImpl
     *
     * ******************************************************************************/
    public static class FactoryWrapperImpl implements LayoutInflater.Factory {
        private LayoutInflater.Factory mFactory;
        private FactoryWrapperImpl(LayoutInflater.Factory factory) {
            mFactory = factory;
        }

        @Override
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            View v = mFactory.onCreateView(name,context,attrs);
            InjectedInflaterBase.handleOnCreateView(v, name, attrs);
            return v;
        }
        public static LayoutInflater.Factory wrap(LayoutInflater.Factory factory){
            return new FactoryWrapperImpl(factory);
        }
    }

    /********************************************************************************
     *
     * Factory2WrapperImpl
     *
     * ******************************************************************************/
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class Factory2WrapperImpl implements LayoutInflater.Factory2 {
        private LayoutInflater.Factory2 mFactory;

        private Factory2WrapperImpl(LayoutInflater.Factory2 factory) {
            mFactory = factory;
        }

        @Override
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            View v = mFactory.onCreateView(name,context,attrs);
            InjectedInflaterBase.handleOnCreateView(v, name, attrs);
            return v;
        }

        @Override
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
            View v = mFactory.onCreateView(name,context,attrs);
            InjectedInflaterBase.handleOnCreateView(v, name, attrs);
            return v;
        }

        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public static LayoutInflater.Factory2 wrap(LayoutInflater.Factory2 factory){
            return new Factory2WrapperImpl(factory);
        }
    }

    /********************************************************************************
     *
     * PrivateFactoryWrapperImpl
     *
     * ******************************************************************************/
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class PrivateFactoryWrapperImpl extends LastChance2Inflater implements LayoutInflater.Factory2 {
        private LayoutInflater.Factory2 mFactory;

        private PrivateFactoryWrapperImpl(LayoutInflater.Factory2 factory, InjectedInflaterBase inflater) {
            super(inflater);
            mFactory = factory;
        }

        @Override
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            View v = mFactory.onCreateView(name,context,attrs);
            if ( v == null ) v = lastChance2CreateView(null, name, context, attrs);
            InjectedInflaterBase.handleOnCreateView(v, name, attrs);
            return v;
        }

        @Override
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
            View v = mFactory.onCreateView(name,context,attrs);
            if ( v == null ) v = lastChance2CreateView(parent, name, context, attrs);
            InjectedInflaterBase.handleOnCreateView(v, name, attrs);
            return v;
        }

        public LayoutInflater.Factory2 getCoreFactory() {
            return mFactory;
        }

        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public static LayoutInflater.Factory2 wrap(LayoutInflater.Factory2 factory
                , InjectedInflaterBase inflater){
            return new PrivateFactoryWrapperImpl(factory,inflater);
        }
    }
}