<commit_before>package com.mixpanel.android.viewcrawler;

import android.graphics.BitmapFactory;
import android.util.Base64;
import android.view.View;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/* package */ class EditProtocol {

    public static class BadInstructionsException extends Exception {
        public BadInstructionsException(String message) {
            super(message);
        }

        public BadInstructionsException(String message, Exception e) {
            super(message, e);
        }
    }

    public ViewVisitor readEventBinding(JSONObject source, ViewVisitor.OnVisitedListener listener)
        throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            final List<ViewVisitor.PathElement> path = readPath(pathDesc);

            if (path.size() == 0) {
                throw new BadInstructionsException("Path selector was empty.");
            }

            final String eventName = source.getString("event_name");
            final String eventType = source.getString("event_type");
            if ("click".equals(eventType)) {
                return new ViewVisitor.AddListenerVisitor(path, eventName, listener);
            } else if ("detected".equals(eventType)) {
                return new ViewVisitor.ViewDetectorVisitor(path, eventName, listener);
            } else {
                throw new BadInstructionsException("Mixpanel can't track event type \"" + eventType + "\"");
            }
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't interpret instructions due to JSONException", e);
        }
    }

    public ViewVisitor readEdit(JSONObject source)
            throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            final List<ViewVisitor.PathElement> path = readPath(pathDesc);

            if (path.size() == 0) {
                throw new BadInstructionsException("Path selector was empty.");
            }

            final ViewVisitor.PathElement pathEnd = path.get(path.size() - 1);
            final String targetClassName = pathEnd.viewClassName;
            final Class targetClass;
            try {
                targetClass = Class.forName(targetClassName);
            } catch (ClassNotFoundException e) {
                throw new BadInstructionsException("Can't find class for visit path: " + targetClassName, e);
            }

            final PropertyDescription prop = readPropertyDescription(targetClass, source.getJSONObject("property"));

            final JSONArray argsAndTypes = source.getJSONArray("args");
            final Object[] methodArgs = new Object[argsAndTypes.length()];
            for (int i = 0; i < argsAndTypes.length(); i++) {
                final JSONArray argPlusType = argsAndTypes.getJSONArray(i);
                final Object jsonArg = argPlusType.get(0);
                final String argType = argPlusType.getString(1);
                methodArgs[i] = convertArgument(jsonArg, argType);
            }

            final Caller mutator = prop.makeMutator(methodArgs);
            if (null == mutator) {
                throw new BadInstructionsException("Can't update a read-only property " + prop.name + " (add a mutator to make this work)");
            }

            return new ViewVisitor.PropertySetVisitor(path, mutator, prop.accessor);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't interpret instructions due to JSONException", e);
        }
    }

    public ViewSnapshot readSnapshotConfig(JSONObject source)
            throws BadInstructionsException {
        final List<PropertyDescription> properties = new ArrayList<PropertyDescription>();

        try {
            final JSONObject config = source.getJSONObject("config");
            final JSONArray classes = config.getJSONArray("classes");
            for (int classIx = 0; classIx < classes.length(); classIx++) {
                final JSONObject classDesc = classes.getJSONObject(classIx);
                final String targetClassName = classDesc.getString("name");
                final Class targetClass = Class.forName(targetClassName);

                final JSONArray propertyDescs = classDesc.getJSONArray("properties");
                for (int i = 0; i < propertyDescs.length(); i++) {
                    final JSONObject propertyDesc = propertyDescs.getJSONObject(i);
                    final PropertyDescription desc = readPropertyDescription(targetClass, propertyDesc);
                    properties.add(desc);
                }
            }

            return new ViewSnapshot(properties);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't read snapshot configuration", e);
        } catch (ClassNotFoundException e) {
            throw new BadInstructionsException("Can't resolve types for snapshot configuration", e);
        }
    }

    // Package access FOR TESTING ONLY
    /* package */ List<ViewVisitor.PathElement> readPath(JSONArray pathDesc)
        throws JSONException {
        final List<ViewVisitor.PathElement> path = new ArrayList<ViewVisitor.PathElement>();

        for (int i = 0; i < pathDesc.length(); i++) {
            final JSONObject targetView = pathDesc.getJSONObject(i);
            final String targetViewClass;
            if (targetView.has("view_class")) {
                targetViewClass = targetView.getString("view_class");
            } else {
                targetViewClass = null;
            }

            final int targetIndex;
            if (targetView.has("index")) {
                targetIndex = targetView.getInt("index");
            } else {
                targetIndex = -1;
            }

            final int targetId;
            if (targetView.has("id")) {
                targetId = targetView.getInt("id");
            } else {
                targetId = -1;
            }

            final String targetTag;
            if (targetView.has("tag")) {
                targetTag = targetView.getString("tag");
            } else {
                targetTag = null;
            }

            path.add(new ViewVisitor.PathElement(targetViewClass, targetIndex, targetId, targetTag));
        }

        return path;
    }

    private PropertyDescription readPropertyDescription(Class targetClass, JSONObject propertyDesc)
            throws BadInstructionsException {
        try {
            final String propName = propertyDesc.getString("name");

            Caller accessor = null;
            if (propertyDesc.has("get")) {
                final JSONObject accessorConfig = propertyDesc.getJSONObject("get");
                final String accessorName = accessorConfig.getString("selector");
                final String accessorResultTypeName = accessorConfig.getJSONObject("result").getString("type");
                final Class accessorResultType = Class.forName(accessorResultTypeName);
                accessor = new Caller(accessorName, NO_PARAMS, accessorResultType);
            }

            final String mutatorName;
            if (propertyDesc.has("set")) {
                final JSONObject mutatorConfig = propertyDesc.getJSONObject("set");
                mutatorName = mutatorConfig.getString("selector");
            } else {
                mutatorName = null;
            }

            return new PropertyDescription(propName, targetClass, accessor, mutatorName);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't read property JSON", e);
        } catch (ClassNotFoundException e) {
            throw new BadInstructionsException("Can't read property JSON, relevant arg/return class not found", e);
        }
    }

    private Object convertArgument(Object jsonArgument, String type)
            throws BadInstructionsException {
        // Object is a Boolean, JSONArray, JSONObject, Number, String, or JSONObject.NULL
        try {
            if ("java.lang.CharSequence".equals(type)) { // Because we're assignable
                return (String) jsonArgument;
            } else if ("boolean".equals(type) || "java.lang.Boolean".equals(type)) {
                return (Boolean) jsonArgument;
            } else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
                return ((Number) jsonArgument).intValue();
            } else if ("float".equals(type) || "java.lang.Float".equals(type)) {
                return ((Number) jsonArgument).floatValue();
            } else if ("android.graphics.Bitmap".equals(type)) {
                byte[] bytes = Base64.decode((String) jsonArgument, 0);
                return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            } else {
                throw new BadInstructionsException("Don't know how to interpret type " + type + " (arg was " + jsonArgument + ")");
            }
        } catch (ClassCastException e) {
            throw new BadInstructionsException("Couldn't interpret <" + jsonArgument + "> as " + type);
        }
    }

    private static final Class[] NO_PARAMS = new Class[0];
} // EditProtocol<commit_msg>Declare checked exceptions on the same line as method prototype<commit_after>package com.mixpanel.android.viewcrawler;

import android.graphics.BitmapFactory;
import android.util.Base64;
import android.view.View;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/* package */ class EditProtocol {

    public static class BadInstructionsException extends Exception {
        public BadInstructionsException(String message) {
            super(message);
        }

        public BadInstructionsException(String message, Exception e) {
            super(message, e);
        }
    }

    public ViewVisitor readEventBinding(JSONObject source, ViewVisitor.OnVisitedListener listener) throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            final List<ViewVisitor.PathElement> path = readPath(pathDesc);

            if (path.size() == 0) {
                throw new BadInstructionsException("Path selector was empty.");
            }

            final String eventName = source.getString("event_name");
            final String eventType = source.getString("event_type");
            if ("click".equals(eventType)) {
                return new ViewVisitor.AddListenerVisitor(path, eventName, listener);
            } else if ("detected".equals(eventType)) {
                return new ViewVisitor.ViewDetectorVisitor(path, eventName, listener);
            } else {
                throw new BadInstructionsException("Mixpanel can't track event type \"" + eventType + "\"");
            }
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't interpret instructions due to JSONException", e);
        }
    }

    public ViewVisitor readEdit(JSONObject source) throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            final List<ViewVisitor.PathElement> path = readPath(pathDesc);

            if (path.size() == 0) {
                throw new BadInstructionsException("Path selector was empty.");
            }

            final ViewVisitor.PathElement pathEnd = path.get(path.size() - 1);
            final String targetClassName = pathEnd.viewClassName;
            final Class targetClass;
            try {
                targetClass = Class.forName(targetClassName);
            } catch (ClassNotFoundException e) {
                throw new BadInstructionsException("Can't find class for visit path: " + targetClassName, e);
            }

            final PropertyDescription prop = readPropertyDescription(targetClass, source.getJSONObject("property"));

            final JSONArray argsAndTypes = source.getJSONArray("args");
            final Object[] methodArgs = new Object[argsAndTypes.length()];
            for (int i = 0; i < argsAndTypes.length(); i++) {
                final JSONArray argPlusType = argsAndTypes.getJSONArray(i);
                final Object jsonArg = argPlusType.get(0);
                final String argType = argPlusType.getString(1);
                methodArgs[i] = convertArgument(jsonArg, argType);
            }

            final Caller mutator = prop.makeMutator(methodArgs);
            if (null == mutator) {
                throw new BadInstructionsException("Can't update a read-only property " + prop.name + " (add a mutator to make this work)");
            }

            return new ViewVisitor.PropertySetVisitor(path, mutator, prop.accessor);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't interpret instructions due to JSONException", e);
        }
    }

    public ViewSnapshot readSnapshotConfig(JSONObject source) throws BadInstructionsException {
        final List<PropertyDescription> properties = new ArrayList<PropertyDescription>();

        try {
            final JSONObject config = source.getJSONObject("config");
            final JSONArray classes = config.getJSONArray("classes");
            for (int classIx = 0; classIx < classes.length(); classIx++) {
                final JSONObject classDesc = classes.getJSONObject(classIx);
                final String targetClassName = classDesc.getString("name");
                final Class targetClass = Class.forName(targetClassName);

                final JSONArray propertyDescs = classDesc.getJSONArray("properties");
                for (int i = 0; i < propertyDescs.length(); i++) {
                    final JSONObject propertyDesc = propertyDescs.getJSONObject(i);
                    final PropertyDescription desc = readPropertyDescription(targetClass, propertyDesc);
                    properties.add(desc);
                }
            }

            return new ViewSnapshot(properties);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't read snapshot configuration", e);
        } catch (ClassNotFoundException e) {
            throw new BadInstructionsException("Can't resolve types for snapshot configuration", e);
        }
    }

    // Package access FOR TESTING ONLY
    /* package */ List<ViewVisitor.PathElement> readPath(JSONArray pathDesc) throws JSONException {
        final List<ViewVisitor.PathElement> path = new ArrayList<ViewVisitor.PathElement>();

        for (int i = 0; i < pathDesc.length(); i++) {
            final JSONObject targetView = pathDesc.getJSONObject(i);
            final String targetViewClass;
            if (targetView.has("view_class")) {
                targetViewClass = targetView.getString("view_class");
            } else {
                targetViewClass = null;
            }

            final int targetIndex;
            if (targetView.has("index")) {
                targetIndex = targetView.getInt("index");
            } else {
                targetIndex = -1;
            }

            final int targetId;
            if (targetView.has("id")) {
                targetId = targetView.getInt("id");
            } else {
                targetId = -1;
            }

            final String targetTag;
            if (targetView.has("tag")) {
                targetTag = targetView.getString("tag");
            } else {
                targetTag = null;
            }

            path.add(new ViewVisitor.PathElement(targetViewClass, targetIndex, targetId, targetTag));
        }

        return path;
    }

    private PropertyDescription readPropertyDescription(Class targetClass, JSONObject propertyDesc) throws BadInstructionsException {
        try {
            final String propName = propertyDesc.getString("name");

            Caller accessor = null;
            if (propertyDesc.has("get")) {
                final JSONObject accessorConfig = propertyDesc.getJSONObject("get");
                final String accessorName = accessorConfig.getString("selector");
                final String accessorResultTypeName = accessorConfig.getJSONObject("result").getString("type");
                final Class accessorResultType = Class.forName(accessorResultTypeName);
                accessor = new Caller(accessorName, NO_PARAMS, accessorResultType);
            }

            final String mutatorName;
            if (propertyDesc.has("set")) {
                final JSONObject mutatorConfig = propertyDesc.getJSONObject("set");
                mutatorName = mutatorConfig.getString("selector");
            } else {
                mutatorName = null;
            }

            return new PropertyDescription(propName, targetClass, accessor, mutatorName);
        } catch (JSONException e) {
            throw new BadInstructionsException("Can't read property JSON", e);
        } catch (ClassNotFoundException e) {
            throw new BadInstructionsException("Can't read property JSON, relevant arg/return class not found", e);
        }
    }

    private Object convertArgument(Object jsonArgument, String type) throws BadInstructionsException {
        // Object is a Boolean, JSONArray, JSONObject, Number, String, or JSONObject.NULL
        try {
            if ("java.lang.CharSequence".equals(type)) { // Because we're assignable
                return (String) jsonArgument;
            } else if ("boolean".equals(type) || "java.lang.Boolean".equals(type)) {
                return (Boolean) jsonArgument;
            } else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
                return ((Number) jsonArgument).intValue();
            } else if ("float".equals(type) || "java.lang.Float".equals(type)) {
                return ((Number) jsonArgument).floatValue();
            } else if ("android.graphics.Bitmap".equals(type)) {
                byte[] bytes = Base64.decode((String) jsonArgument, 0);
                return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            } else {
                throw new BadInstructionsException("Don't know how to interpret type " + type + " (arg was " + jsonArgument + ")");
            }
        } catch (ClassCastException e) {
            throw new BadInstructionsException("Couldn't interpret <" + jsonArgument + "> as " + type);
        }
    }

    private static final Class[] NO_PARAMS = new Class[0];
} // EditProtocol
{'fraction_non_alphanumeric': 0.09553042541733979, 'fraction_numerical': 0.0019386106623586429, 'mean_word_length': 2.2207769684356573, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5011818', 'n_tokens_mistral': 4541, 'n_tokens_neox': 4348, 'n_words': 1146}