/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.arch.lifecycle;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;

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

/**
 * Internal class to handle lifecycle conversion etc.
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class Lifecycling {
    private static Constructor<? extends GenericLifecycleObserver> sREFLECTIVE;

    static {
        try {
            sREFLECTIVE = ReflectiveGenericLifecycleObserver.class.getConstructor(Object.class);
        } catch (NoSuchMethodException ignored) {

        }
    }

    private static Map<Class, Constructor<? extends GenericLifecycleObserver>> sCallbackCache =
            new HashMap<>();

    @NonNull
    static GenericLifecycleObserver getCallback(Object object) {
        if (object instanceof GenericLifecycleObserver) {
            return (GenericLifecycleObserver) object;
        }
        //noinspection TryWithIdenticalCatches
        try {
            final Class<?> klass = object.getClass();
            Constructor<? extends GenericLifecycleObserver> cachedConstructor = sCallbackCache.get(
                    klass);
            if (cachedConstructor != null) {
                return cachedConstructor.newInstance(object);
            }
            cachedConstructor = getGeneratedAdapterConstructor(klass);
            if (cachedConstructor != null) {
                sCallbackCache.put(klass, cachedConstructor);
                if (!cachedConstructor.isAccessible()) {
                    cachedConstructor.setAccessible(true);
                }
                return cachedConstructor.newInstance(object);
            } else {
                sCallbackCache.put(klass, sREFLECTIVE);
            }
            return new ReflectiveGenericLifecycleObserver(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

    }

    @Nullable
    private static Constructor<? extends GenericLifecycleObserver> getGeneratedAdapterConstructor(
            Class<?> klass) {
        final String fullPackage = klass.getPackage().getName();

        String name = klass.getCanonicalName();
        // anonymous class bug:35073837
        if (name == null) {
            return null;
        }
        final String adapterName = getAdapterName(fullPackage.isEmpty() ? name :
                name.substring(fullPackage.length() + 1));
        try {
            @SuppressWarnings("unchecked")
            final Class<? extends GenericLifecycleObserver> aClass =
                    (Class<? extends GenericLifecycleObserver>) Class.forName(
                            fullPackage.isEmpty() ? adapterName : fullPackage + "." + adapterName);
            return aClass.getDeclaredConstructor(klass);
        } catch (ClassNotFoundException e) {
            final Class<?> superclass = klass.getSuperclass();
            if (superclass != null) {
                return getGeneratedAdapterConstructor(superclass);
            }
        } catch (NoSuchMethodException e) {
            // this should not happen
            throw new RuntimeException(e);
        }
        return null;
    }

    static String getAdapterName(String className) {
        return className.replace(".", "_") + "_LifecycleAdapter";
    }
}

@@ -1229,20 +1229,49 @@
 er.class
-.get
+%0A                    .getDeclared
 Construc
@@ -2167,70 +2167,8 @@
 ) %7B%0A
-                sCallbackCache.put(klass, cachedConstructor);%0A
     
@@ -2313,56 +2313,64 @@
     
-    return cachedConstructor.newInstance(object)
+%7D else %7B%0A                cachedConstructor = sREFLECTIVE
 ;%0A  
@@ -2376,36 +2376,25 @@
            %7D
- else %7B%0A    
+%0A
             
@@ -2423,44 +2423,40 @@
 ss, 
-sREFLECTIVE);%0A            %7D%0A
+cachedConstructor);%0A    
         
     
@@ -2455,57 +2455,44 @@
     
-    
 return 
-new ReflectiveGenericLifecycleObserver
+cachedConstructor.newInstance
 (obj
@@ -2770,25 +2770,24 @@
 ;%0A        %7D%0A
-%0A
     %7D%0A%0A    @

Fix initialization of sREFLECTIVE