<commit_before>package io.keen.client.java;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Implementation of the {@link io.keen.client.java.KeenEventStore} interface using the file system
 * to cache events in between queueing and batch posting.
 *
 * @author <NAME> (<EMAIL>)
 * @since 2.0.0
 */
public class FileEventStore implements KeenAttemptCountingEventStore {

    ///// PUBLIC CONSTRUCTORS /////

    /**
     * Constructs a new File-based event store.
     *
     * @param root The root directory in which to store queued event files.
     * @throws IOException If the provided {@code root} isn't an existing directory.
     */
    public FileEventStore(File root) throws IOException {
        if (!root.exists() || !root.isDirectory()) {
            throw new IOException("Event store root '" + root + "' must exist and be a directory");
        }

        this.root = root;
    }

    ///// PUBLIC METHODS /////

    /**
     * {@inheritDoc}
     */
    @Override
    public Object store(String projectId, String eventCollection,
                        String event) throws IOException {
        // Prepare the collection cache directory.
        File collectionCacheDir = prepareCollectionDir(projectId, eventCollection);

        // Create the cache file.
        Calendar timestamp = Calendar.getInstance();
        File cacheFile = getFileForEvent(collectionCacheDir, timestamp);

        // Write the event to the cache file.
        Writer writer = null;
        try {
            OutputStream out = new FileOutputStream(cacheFile);
            writer = new OutputStreamWriter(out, ENCODING);
            writer.write(event);
        } finally {
            KeenUtils.closeQuietly(writer);
        }

        // Return the file as the handle to use for retrieving/removing the event.
        return cacheFile;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String get(Object handle) throws IOException {
        if (!(handle instanceof File)) {
            throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
        }

        File eventFile = (File) handle;
        if (eventFile.exists() && eventFile.isFile()) {
            return KeenUtils.convertFileToString(eventFile);
        } else {
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void remove(Object handle) throws IOException {
        if (!(handle instanceof File)) {
            throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
        }

        File eventFile = (File) handle;
        if (eventFile.exists() && eventFile.isFile()) {
            if (eventFile.delete()) {
                KeenLogging.log(String.format(Locale.US, "Successfully deleted file: %s",
                        eventFile.getAbsolutePath()));
            } else {
                KeenLogging.log(String.format(Locale.US,
                        "CRITICAL ERROR: Could not remove event at %s",
                        eventFile.getAbsolutePath()));
            }
        } else {
            KeenLogging.log(String.format(Locale.US, "WARNING: no event found at %s",
                    eventFile.getAbsolutePath()));
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, List<Object>> getHandles(String projectId) throws IOException {
        File projectDir = getProjectDir(projectId, false);
        if (projectDir.exists() && projectDir.isDirectory()) {
            return getHandlesFromProjectDirectory(projectDir);
        } else {
            return new HashMap<String, List<Object>>();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getAttempts(String projectId, String eventCollection) throws IOException {
        File projectDir = getProjectDir(projectId, false);
        File collectionDir = new File(projectDir, eventCollection);
        File attemptsFile = new File(collectionDir, "__attempts.json");
        return get(attemptsFile);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setAttempts(String projectId, String eventCollection, String attemptsString) throws IOException {
        // Prepare the collection cache directory.
        File collectionCacheDir = prepareCollectionDir(projectId, eventCollection);

        // Create the cache file.
        File cacheFile = new File(collectionCacheDir, "__attempts.json");

        // Write the event to the cache file.
        Writer writer = null;
        try {
            OutputStream out = new FileOutputStream(cacheFile);
            writer = new OutputStreamWriter(out, ENCODING);
            writer.write(attemptsString);
        } finally {
            KeenUtils.closeQuietly(writer);
        }
    }

    ///// PRIVATE CONSTANTS /////

    /**
     * The encoding to use when writing events to files.
     */
    private static final String ENCODING = "UTF-8";

    /**
     * The number of events that can be stored for a single collection before aging them out.
     */
    private static final int MAX_EVENTS_PER_COLLECTION = 10000;

    /**
     * The number of events to drop when aging out.
     */
    private static final int NUMBER_EVENTS_TO_FORGET = 100;

    ///// PRIVATE FIELDS /////<commit_msg>Make the __attempts.json file name into a constant.<commit_after>package io.keen.client.java;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Implementation of the {@link io.keen.client.java.KeenEventStore} interface using the file system
 * to cache events in between queueing and batch posting.
 *
 * @author <NAME> (<EMAIL>)
 * @since 2.0.0
 */
public class FileEventStore implements KeenAttemptCountingEventStore {

    ///// PUBLIC CONSTRUCTORS /////

    /**
     * Constructs a new File-based event store.
     *
     * @param root The root directory in which to store queued event files.
     * @throws IOException If the provided {@code root} isn't an existing directory.
     */
    public FileEventStore(File root) throws IOException {
        if (!root.exists() || !root.isDirectory()) {
            throw new IOException("Event store root '" + root + "' must exist and be a directory");
        }

        this.root = root;
    }

    ///// PUBLIC METHODS /////

    /**
     * {@inheritDoc}
     */
    @Override
    public Object store(String projectId, String eventCollection,
                        String event) throws IOException {
        // Prepare the collection cache directory.
        File collectionCacheDir = prepareCollectionDir(projectId, eventCollection);

        // Create the cache file.
        Calendar timestamp = Calendar.getInstance();
        File cacheFile = getFileForEvent(collectionCacheDir, timestamp);

        // Write the event to the cache file.
        Writer writer = null;
        try {
            OutputStream out = new FileOutputStream(cacheFile);
            writer = new OutputStreamWriter(out, ENCODING);
            writer.write(event);
        } finally {
            KeenUtils.closeQuietly(writer);
        }

        // Return the file as the handle to use for retrieving/removing the event.
        return cacheFile;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String get(Object handle) throws IOException {
        if (!(handle instanceof File)) {
            throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
        }

        File eventFile = (File) handle;
        if (eventFile.exists() && eventFile.isFile()) {
            return KeenUtils.convertFileToString(eventFile);
        } else {
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void remove(Object handle) throws IOException {
        if (!(handle instanceof File)) {
            throw new IllegalArgumentException("Expected File, but was " + handle.getClass());
        }

        File eventFile = (File) handle;
        if (eventFile.exists() && eventFile.isFile()) {
            if (eventFile.delete()) {
                KeenLogging.log(String.format(Locale.US, "Successfully deleted file: %s",
                        eventFile.getAbsolutePath()));
            } else {
                KeenLogging.log(String.format(Locale.US,
                        "CRITICAL ERROR: Could not remove event at %s",
                        eventFile.getAbsolutePath()));
            }
        } else {
            KeenLogging.log(String.format(Locale.US, "WARNING: no event found at %s",
                    eventFile.getAbsolutePath()));
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, List<Object>> getHandles(String projectId) throws IOException {
        File projectDir = getProjectDir(projectId, false);
        if (projectDir.exists() && projectDir.isDirectory()) {
            return getHandlesFromProjectDirectory(projectDir);
        } else {
            return new HashMap<String, List<Object>>();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getAttempts(String projectId, String eventCollection) throws IOException {
        File projectDir = getProjectDir(projectId, false);
        File collectionDir = new File(projectDir, eventCollection);
        File attemptsFile = new File(collectionDir, ATTEMPTS_JSON_FILE_NAME);
        return get(attemptsFile);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setAttempts(String projectId, String eventCollection, String attemptsString) throws IOException {
        // Prepare the collection cache directory.
        File collectionCacheDir = prepareCollectionDir(projectId, eventCollection);

        // Create the cache file.
        File cacheFile = new File(collectionCacheDir, ATTEMPTS_JSON_FILE_NAME);

        // Write the event to the cache file.
        Writer writer = null;
        try {
            OutputStream out = new FileOutputStream(cacheFile);
            writer = new OutputStreamWriter(out, ENCODING);
            writer.write(attemptsString);
        } finally {
            KeenUtils.closeQuietly(writer);
        }
    }

    ///// PRIVATE CONSTANTS /////

    /**
     * The encoding to use when writing events to files.
     */
    private static final String ENCODING = "UTF-8";

    /**
     * The number of events that can be stored for a single collection before aging them out.
     */
    private static final int MAX_EVENTS_PER_COLLECTION = 10000;

    /**
     * The number of events to drop when aging out.
     */
    private static final int NUMBER_EVENTS_TO_FORGET = 100;

    /**
     * The file name of the attempts json data
     */
    private static final String ATTEMPTS_JSON_FILE_NAME = "__attempts.json";

    ///// PRIVATE FIELDS /////
{'fraction_non_alphanumeric': 0.10141162206633758, 'fraction_numerical': 0.0020784619381657575, 'mean_word_length': 2.2603049124788255, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, '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': '6813571', 'n_tokens_mistral': 3082, 'n_tokens_neox': 2963, 'n_words': 877}