package com.mixpanel.android.mpmetrics;

import android.content.Context;
import android.util.SparseArray;

import com.mixpanel.android.util.MPLog;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * This class is for internal use in the Mixpanel library, and should not be imported into
 * client code.
 */
public abstract class ResourceReader implements ResourceIds {

    public static class Ids extends ResourceReader {
        public Ids(String resourcePackageName, Context context) {
            super(context);
            mResourcePackageName = resourcePackageName;
            initialize();
        }

        @Override
        protected Class<?> getSystemClass() {
            return android.R.id.class;
        }

        @Override
        protected String getLocalClassName(Context context) {
            return mResourcePackageName + ".R$id";
        }

        private final String mResourcePackageName;
    }

    public static class Drawables extends ResourceReader {
        protected Drawables(String resourcePackageName, Context context) {
            super(context);
            mResourcePackageName = resourcePackageName;
            initialize();
        }

        @Override
        protected Class<?> getSystemClass() {
            return android.R.drawable.class;
        }

        @Override
        protected String getLocalClassName(Context context) {
            return mResourcePackageName + ".R$drawable";
        }

        private final String mResourcePackageName;
    }

    protected ResourceReader(Context context) {
        mContext = context;
        mIdNameToId = new HashMap<String, Integer>();
        mIdToIdName = new SparseArray<String>();
    }

    @Override
    public boolean knownIdName(String name) {
        return mIdNameToId.containsKey(name);
    }

    @Override
    public int idFromName(String name) {
        return mIdNameToId.get(name);
    }

    @Override
    public String nameForId(int id) {
        return mIdToIdName.get(id);
    }

    private static void readClassIds(Class<?> platformIdClass, String namespace, Map<String, Integer> namesToIds) {
        try {
            final Field[] fields = platformIdClass.getFields();
            for (int i = 0; i < fields.length; i++) {
                final Field field = fields[i];
                final int modifiers = field.getModifiers();
                if (Modifier.isStatic(modifiers)) {
                    final Class fieldType = field.getType();
                    if (fieldType == int.class) {
                        final String name = field.getName();
                        final int value = field.getInt(null);
                        final String namespacedName;
                        if (null == namespace) {
                            namespacedName = name;
                        } else {
                            namespacedName = namespace + ":" + name;
                        }

                        namesToIds.put(namespacedName, value);
                    }
                }
            }
        } catch (IllegalAccessException e) {
            MPLog.e(LOGTAG, "Can't read built-in id names from " + platformIdClass.getName(), e);
        }
    }

    protected abstract Class<?> getSystemClass();
    protected abstract String getLocalClassName(Context context);

    protected void initialize() {
        mIdNameToId.clear();
        mIdToIdName.clear();

        final Class<?> sysIdClass = getSystemClass();
        readClassIds(sysIdClass, "android", mIdNameToId);

        final String localClassName = getLocalClassName(mContext);
        try {
            final Class<?> rIdClass = Class.forName(localClassName);
            readClassIds(rIdClass, null, mIdNameToId);
        } catch (ClassNotFoundException e) {
            MPLog.w(LOGTAG, "Can't load names for Android view ids from '" + localClassName + "', ids by name will not be available in the events editor.");
            MPLog.i(LOGTAG,
                    "You may be missing a Resources class for your package due to your proguard configuration, " +
                            "or you may be using an applicationId in your build that isn't the same as the package declared in your AndroidManifest.xml file.\n" +
                            "If you're using proguard, you can fix this issue by adding the following to your proguard configuration:\n\n" +
                            "-keep class **.R$* {\n" +
                            "    <fields>;\n" +
                            "}\n\n" +
                            "If you're not using proguard, or if your proguard configuration already contains the directive above, " +
                            "you can add the following to your AndroidManifest.xml file to explicitly point the Mixpanel library to " +
                            "the appropriate library for your resources class:\n\n" +
                            "<meta-data android:name=\"com.mixpanel.android.MPConfig.ResourcePackageName\" android:value=\"YOUR_PACKAGE_NAME\" />\n\n" +
                            "where YOUR_PACKAGE_NAME is the same string you use for the \"package\" attribute in your <manifest> tag."
            );
        }

        for (Map.Entry<String, Integer> idMapping : mIdNameToId.entrySet()) {
            mIdToIdName.put(idMapping.getValue(), idMapping.getKey());
        }
    }

    private final Context mContext;
    private final Map<String, Integer> mIdNameToId;
    private final SparseArray<String> mIdToIdName;

    @SuppressWarnings("unused")
    private static final String LOGTAG = "MixpanelAPI.RsrcReader";
}

@@ -2578,24 +2578,58 @@
 nt.class) %7B%0A
+                        try %7B%0A    
             
@@ -2693,32 +2693,36 @@
                 
+ 
+   
 final int value 
@@ -2759,32 +2759,36 @@
                 
+    
 final String nam
@@ -2796,24 +2796,28 @@
 spacedName;%0A
+    
             
@@ -2873,32 +2873,36 @@
                 
+    
 namespacedName =
@@ -2932,16 +2932,20 @@
         
+    
 %7D else %7B
@@ -2945,16 +2945,20 @@
  else %7B%0A
+    
         
@@ -3034,35 +3034,43 @@
                 
-%7D%0A%0A
+    %7D%0A%0A    
                 
@@ -3112,24 +3112,319 @@
 me, value);%0A
+                        %7D catch (ArrayIndexOutOfBoundsException e) %7B%0A                            // https://github.com/mixpanel/mixpanel-android/issues/241%0A                            MPLog.e(LOGTAG, %22Can't read built-in id name from %22 + platformIdClass.getName(), e);%0A                        %7D%0A
             

Add try/catch for OEM crashes in ResourceReader (#653)