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

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

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 readEdit(JSONObject source, ViewVisitor.OnVisitedListener listener)
            throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            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 = targetView.getString("view_class");
                final int targetIndex = targetView.getInt("index");
                path.add(new ViewVisitor.PathElement(targetViewClass, targetIndex));
            }

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

            if (source.has("property")) {
                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);
            } else if (source.has("event_name")) {
                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 + "\"");
                }
            }

            throw new BadInstructionsException("Instructions contained neither a method to call nor an event to track");
        } 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 JSONArray classes = source.getJSONArray("classes");<commit_msg>Slightly more like the real UI protocol<commit_after>package com.mixpanel.android.viewcrawler;

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

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 readEdit(JSONObject source, ViewVisitor.OnVisitedListener listener)
            throws BadInstructionsException {
        try {
            final JSONArray pathDesc = source.getJSONArray("path");
            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 = targetView.getString("view_class");
                final int targetIndex = targetView.getInt("index");
                path.add(new ViewVisitor.PathElement(targetViewClass, targetIndex));
            }

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

            if (source.has("property")) {
                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);
            } else if (source.has("event_name")) {
                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 + "\"");
                }
            }

            throw new BadInstructionsException("Instructions contained neither a method to call nor an event to track");
        } 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");
{'fraction_non_alphanumeric': 0.08895486935866984, 'fraction_numerical': 0.0019002375296912114, 'mean_word_length': 2.1909814323607426, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, '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': '6439592', 'n_tokens_mistral': 2030, 'n_tokens_neox': 1916, 'n_words': 519}