<commit_before>package com.hokolinks.utils.networking.async;

import com.hokolinks.Hoko;
import com.hokolinks.model.App;
import com.hokolinks.model.exceptions.HokoException;
import com.hokolinks.utils.log.HokoLog;
import com.hokolinks.utils.networking.Networking;

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;

/**
 * HttpRequest is a savable model around HttpRequests.
 * It contains the path, an operation type, parameters in the form of json and the number of
 * retries.
 */
public class HttpRequest implements Serializable {

    // Constants
    private static final int TASK_TIMEOUT = 15000; // millis
    private static final String TASK_VERSION = "v2";
    private static final String TASK_FORMAT = "json";

    private static String sTaskEndpoint = "https://api.hokolinks.com";

    // Properties
    private HokoNetworkOperationType mOperationType;
    private String mUrl;
    private String mToken;
    private String mParameters;
    private int mNumberOfRetries;

    /**
     * Creates a request with a type, path, token and parameters.
     *
     * @param operationType The operation type (e.g. GET/PUT/POST).
     * @param url           The url (e.g. "https://api.hokolinks.com/v1/routes.json").
     * @param token         The application token.
     * @param parameters    The parameters in json string form.
     */
    public HttpRequest(HokoNetworkOperationType operationType, String url, String token,
                       String parameters) {
        mOperationType = operationType;
        mUrl = url.contains("http") ? url : HttpRequest.getURLFromPath(url);
        mToken = token;
        mParameters = parameters;
        mNumberOfRetries = 0;
    }

    // Constructors

    public static void setEndpoint(String endpoint) {
        sTaskEndpoint = endpoint;
    }

    /**
     * Generates the full URL, merging the endpoint, version, path and format.
     *
     * @param path The path component.
     * @return The full URL.
     */
    public static String getURLFromPath(String path) {
        return sTaskEndpoint + "/" + TASK_VERSION + "/" + path + "."
                + TASK_FORMAT;
    }

    private static String urlEncode(String url, String jsonString) {
        if (jsonString == null) {
            return url;
        }

        String finalURL = url;
        try {
            JSONObject jsonObject = new JSONObject(jsonString);
            if (jsonObject.names().length() > 0) {
                finalURL += "?";
            }
            for (Iterator<String> iterator = jsonObject.keys(); iterator.hasNext(); ) {
                String key = iterator.next();
                finalURL += key + "=" + jsonObject.getString(key);
                if (iterator.hasNext()) {
                    finalURL += "&";
                }
            }
        } catch (JSONException e) {
            HokoLog.e(e);
        }
        return finalURL;
    }

    // Property Gets
    public HokoNetworkOperationType getOperationType() {
        return mOperationType;
    }

    public URL getUrl() {
        try {
            if (mOperationType != HokoNetworkOperationType.GET) {
                return new URL(mUrl);
            } else {
                return new URL(urlEncode(mUrl, getParameters()));
            }
        } catch (MalformedURLException e) {
            HokoLog.e(e);
        }
        return null;
    }

    public String getToken() {
        return mToken;
    }

    // Runnable

    public String getParameters() {
        return mParameters;
    }

    public int getNumberOfRetries() {
        return mNumberOfRetries;
    }

    // Networking

    public void incrementNumberOfRetries() {
        mNumberOfRetries++;
    }

    /**
     * Transforms the HttpRequest to a Runnable object so it can execute the request
     * on a background thread, usually inside a NetworkAsyncTask object.
     *
     * @return The runnable wrapper for the request.
     */
    public Runnable toRunnable() {
        return toRunnable(null);
    }

    /**
     * Transforms the HttpRequest to a Runnable object with a callback so it can execute the
     * request on a background thread, usually inside a NetworkAsyncTask object. It will then call
     * the callback functions accordingly.
     *
     * @param httpCallback  The HttpRequestCallback object.e
     * @return The runnable wrapper for the request.
     */
    public Runnable toRunnable(final HttpRequestCallback httpCallback) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    switch (mOperationType) {
                        case GET:
                            performGET(httpCallback);
                            break;
                        case POST:
                            performPOST(httpCallback);
                            break;
                        case PUT:
                            performPUT(httpCallback);
                            break;
                        default:
                            break;
                    }
                } catch (IOException e) {
                    HokoLog.e(e);
                    if (httpCallback != null)
                        httpCallback.onFailure(e);
                }
            }
        };
    }

    private void applyHeaders(HttpURLConnection connection, boolean postOrPut) {
        connection.setConnectTimeout(TASK_TIMEOUT);
        connection.setReadTimeout(TASK_TIMEOUT);
        connection.setRequestProperty("Accept", "application/json");
        connection.setRequestProperty("Accept-Encoding", "gzip, deflate");
        if (postOrPut) {
            connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        }
        if (getToken() != null) {
            connection.setRequestProperty("Authorization", "Token " + getToken());
            connection.setRequestProperty("Hoko-SDK-Version", Hoko.VERSION);
            if (Networking.getNetworking() != null)
                connection.setRequestProperty("Hoko-SDK-Env",
                        App.getEnvironment(Networking.getNetworking().getContext()));
        }
    }

    /**
     * Performs an HttpGet to the specified url, will handle the response with the callback.
     *
     * @param httpCallback  The HttpRequestCallback object.
     * @throws IOException  Throws an IOException in case of a network problem.
     */<commit_msg>Added new SDK User-Agent<commit_after>package com.hokolinks.utils.networking.async;

import com.hokolinks.Hoko;
import com.hokolinks.model.App;
import com.hokolinks.model.Device;
import com.hokolinks.model.exceptions.HokoException;
import com.hokolinks.utils.log.HokoLog;
import com.hokolinks.utils.networking.Networking;

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;

/**
 * HttpRequest is a savable model around HttpRequests.
 * It contains the path, an operation type, parameters in the form of json and the number of
 * retries.
 */
public class HttpRequest implements Serializable {

    // Constants
    private static final int TASK_TIMEOUT = 15000; // millis
    private static final String TASK_VERSION = "v2";
    private static final String TASK_FORMAT = "json";

    private static String sTaskEndpoint = "https://api.hokolinks.com";

    // Properties
    private HokoNetworkOperationType mOperationType;
    private String mUrl;
    private String mToken;
    private String mParameters;
    private int mNumberOfRetries;

    /**
     * Creates a request with a type, path, token and parameters.
     *
     * @param operationType The operation type (e.g. GET/PUT/POST).
     * @param url           The url (e.g. "https://api.hokolinks.com/v1/routes.json").
     * @param token         The application token.
     * @param parameters    The parameters in json string form.
     */
    public HttpRequest(HokoNetworkOperationType operationType, String url, String token,
                       String parameters) {
        mOperationType = operationType;
        mUrl = url.contains("http") ? url : HttpRequest.getURLFromPath(url);
        mToken = token;
        mParameters = parameters;
        mNumberOfRetries = 0;
    }

    // Constructors

    public static void setEndpoint(String endpoint) {
        sTaskEndpoint = endpoint;
    }

    /**
     * Generates the full URL, merging the endpoint, version, path and format.
     *
     * @param path The path component.
     * @return The full URL.
     */
    public static String getURLFromPath(String path) {
        return sTaskEndpoint + "/" + TASK_VERSION + "/" + path + "."
                + TASK_FORMAT;
    }

    private static String getUserAgent() {
        String environment = "";
        if (Networking.getNetworking() != null)
            environment = App.getEnvironment(Networking.getNetworking().getContext());

        return "HOKO/" + Hoko.VERSION + " (" + environment + "; Linux; " + Device.getPlatform() + " " +
                Device.getSystemVersion() + "; " + Device.getVendor() + " " + Device.getModel() + ")";
    }

    private static String urlEncode(String url, String jsonString) {
        if (jsonString == null) {
            return url;
        }

        String finalURL = url;
        try {
            JSONObject jsonObject = new JSONObject(jsonString);
            if (jsonObject.names().length() > 0) {
                finalURL += "?";
            }
            for (Iterator<String> iterator = jsonObject.keys(); iterator.hasNext(); ) {
                String key = iterator.next();
                finalURL += key + "=" + jsonObject.getString(key);
                if (iterator.hasNext()) {
                    finalURL += "&";
                }
            }
        } catch (JSONException e) {
            HokoLog.e(e);
        }
        return finalURL;
    }

    // Property Gets
    public HokoNetworkOperationType getOperationType() {
        return mOperationType;
    }

    public URL getUrl() {
        try {
            if (mOperationType != HokoNetworkOperationType.GET) {
                return new URL(mUrl);
            } else {
                return new URL(urlEncode(mUrl, getParameters()));
            }
        } catch (MalformedURLException e) {
            HokoLog.e(e);
        }
        return null;
    }

    public String getToken() {
        return mToken;
    }

    // Runnable

    public String getParameters() {
        return mParameters;
    }

    public int getNumberOfRetries() {
        return mNumberOfRetries;
    }

    // Networking

    public void incrementNumberOfRetries() {
        mNumberOfRetries++;
    }

    /**
     * Transforms the HttpRequest to a Runnable object so it can execute the request
     * on a background thread, usually inside a NetworkAsyncTask object.
     *
     * @return The runnable wrapper for the request.
     */
    public Runnable toRunnable() {
        return toRunnable(null);
    }

    /**
     * Transforms the HttpRequest to a Runnable object with a callback so it can execute the
     * request on a background thread, usually inside a NetworkAsyncTask object. It will then call
     * the callback functions accordingly.
     *
     * @param httpCallback  The HttpRequestCallback object.e
     * @return The runnable wrapper for the request.
     */
    public Runnable toRunnable(final HttpRequestCallback httpCallback) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    switch (mOperationType) {
                        case GET:
                            performGET(httpCallback);
                            break;
                        case POST:
                            performPOST(httpCallback);
                            break;
                        case PUT:
                            performPUT(httpCallback);
                            break;
                        default:
                            break;
                    }
                } catch (IOException e) {
                    HokoLog.e(e);
                    if (httpCallback != null)
                        httpCallback.onFailure(e);
                }
            }
        };
    }

    private void applyHeaders(HttpURLConnection connection, boolean postOrPut) {
        connection.setConnectTimeout(TASK_TIMEOUT);
        connection.setReadTimeout(TASK_TIMEOUT);
        connection.setRequestProperty("Accept", "application/json");
        connection.setRequestProperty("Accept-Encoding", "gzip, deflate");
        if (postOrPut) {
            connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        }
        if (getToken() != null) {
            connection.setRequestProperty("Authorization", "Token " + getToken());
            connection.setRequestProperty("Hoko-SDK-Version", Hoko.VERSION);
            connection.setRequestProperty("User-Agent", HttpRequest.getUserAgent());
            if (Networking.getNetworking() != null)
                connection.setRequestProperty("Hoko-SDK-Env",
                        App.getEnvironment(Networking.getNetworking().getContext()));
        }
    }

    /**
     * Performs an HttpGet to the specified url, will handle the response with the callback.
     *
     * @param httpCallback  The HttpRequestCallback object.
     * @throws IOException  Throws an IOException in case of a network problem.
     */
{'fraction_non_alphanumeric': 0.09113387495584599, 'fraction_numerical': 0.001412928293889085, 'mean_word_length': 1.9814658803706824, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 4, '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': '3022122', 'n_tokens_mistral': 3744, 'n_tokens_neox': 3622, 'n_words': 979}