<commit_before>package org.sugr.gearshift.datasource;

import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import org.sugr.gearshift.G;
import org.sugr.gearshift.R;
import org.sugr.gearshift.core.Torrent;
import org.sugr.gearshift.core.TransmissionSession;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class TorrentValues {
    public ContentValues torrent;
    public List<ContentValues> files;
    public List<ContentValues> trackers;
    public List<ContentValues> peers;
}

class TorrentCursorArgs {
    public String selection;
    public String[] selectionArgs;
    public String orderBy;
}

public class DataSource {
    private SQLiteDatabase database;

    private SQLiteOpenHelper dbHelper;
    private Context context;

    /* Transmission stuff */
    private static final int NEW_STATUS_RPC_VERSION = 14;

    private TransmissionSession session;

    public DataSource(Context context) {
        setContext(context);
        setHelper(new SQLiteHelper(context.getApplicationContext()));
    }

    public DataSource(Context context, SQLiteOpenHelper helper) {
        setContext(context);
        setHelper(helper);
    }

    public void open() {
        synchronized (DataSource.class) {
            database = dbHelper.getWritableDatabase();
        }
    }

    public void close() {
        synchronized (DataSource.class) {
            dbHelper.close();
            database = null;
        }
    }

    public boolean isOpen() {
        return database != null && database.isOpen();
    }

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public void setHelper(SQLiteOpenHelper helper) {
        this.dbHelper = helper;
    }

    public boolean updateSession(String profile, JsonParser parser) throws IOException {
        if (!isOpen())
            return false;

        List<ContentValues> session = jsonToSessionValues(profile, parser);

        synchronized (DataSource.class) {
            database.beginTransactionNonExclusive();
            try {
                for (ContentValues item : session) {
                    database.insertWithOnConflict(Constants.T_SESSION, null,
                        item, SQLiteDatabase.CONFLICT_REPLACE);
                }

                database.setTransactionSuccessful();

                return true;
            } finally {
                if (database.inTransaction()) {
                    database.endTransaction();
                }
            }
        }
    }

    public TorrentStatus updateTorrents(String profile, JsonParser parser, boolean removeObsolete)
            throws IOException {
        if (!isOpen())
            return null;

        int[] idChanges = queryTorrentIdChanges();
        int[] status = queryStatusCount();

        if (session == null) {
            session = getSession(profile);
        }

        synchronized (DataSource.class) {
            database.beginTransactionNonExclusive();
            try {
                List<String> validHashStrings = null;
                if (removeObsolete) {
                    validHashStrings = new ArrayList<>();
                    database.delete(Constants.T_TRACKER, null, null);
                }

                while (parser.nextToken() != JsonToken.END_ARRAY) {
                    TorrentValues values = jsonToTorrentValues(parser);

                    String hash = (String) values.torrent.get(Constants.C_HASH_STRING);
                    if (removeObsolete) {
                        validHashStrings.add(hash);
                    }

                    int updated = database.update(
                        Constants.T_TORRENT, values.torrent, Constants.C_HASH_STRING + " = ?",
                        new String[] { hash });

                    if (updated < 1) {
                        database.insertWithOnConflict(Constants.T_TORRENT, null,
                            values.torrent, SQLiteDatabase.CONFLICT_REPLACE);
                    }

                    ContentValues profileValues = new ContentValues();
                    profileValues.put(Constants.C_HASH_STRING, hash);<commit_msg>do not clear all trackers when removing obsolete torrents.<commit_after>package org.sugr.gearshift.datasource;

import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import org.sugr.gearshift.G;
import org.sugr.gearshift.R;
import org.sugr.gearshift.core.Torrent;
import org.sugr.gearshift.core.TransmissionSession;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class TorrentValues {
    public ContentValues torrent;
    public List<ContentValues> files;
    public List<ContentValues> trackers;
    public List<ContentValues> peers;
}

class TorrentCursorArgs {
    public String selection;
    public String[] selectionArgs;
    public String orderBy;
}

public class DataSource {
    private SQLiteDatabase database;

    private SQLiteOpenHelper dbHelper;
    private Context context;

    /* Transmission stuff */
    private static final int NEW_STATUS_RPC_VERSION = 14;

    private TransmissionSession session;

    public DataSource(Context context) {
        setContext(context);
        setHelper(new SQLiteHelper(context.getApplicationContext()));
    }

    public DataSource(Context context, SQLiteOpenHelper helper) {
        setContext(context);
        setHelper(helper);
    }

    public void open() {
        synchronized (DataSource.class) {
            database = dbHelper.getWritableDatabase();
        }
    }

    public void close() {
        synchronized (DataSource.class) {
            dbHelper.close();
            database = null;
        }
    }

    public boolean isOpen() {
        return database != null && database.isOpen();
    }

    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public void setHelper(SQLiteOpenHelper helper) {
        this.dbHelper = helper;
    }

    public boolean updateSession(String profile, JsonParser parser) throws IOException {
        if (!isOpen())
            return false;

        List<ContentValues> session = jsonToSessionValues(profile, parser);

        synchronized (DataSource.class) {
            database.beginTransactionNonExclusive();
            try {
                for (ContentValues item : session) {
                    database.insertWithOnConflict(Constants.T_SESSION, null,
                        item, SQLiteDatabase.CONFLICT_REPLACE);
                }

                database.setTransactionSuccessful();

                return true;
            } finally {
                if (database.inTransaction()) {
                    database.endTransaction();
                }
            }
        }
    }

    public TorrentStatus updateTorrents(String profile, JsonParser parser, boolean removeObsolete)
            throws IOException {
        if (!isOpen())
            return null;

        int[] idChanges = queryTorrentIdChanges();
        int[] status = queryStatusCount();

        if (session == null) {
            session = getSession(profile);
        }

        synchronized (DataSource.class) {
            database.beginTransactionNonExclusive();
            try {
                List<String> validHashStrings = null;
                if (removeObsolete) {
                    validHashStrings = new ArrayList<>();
                }

                while (parser.nextToken() != JsonToken.END_ARRAY) {
                    TorrentValues values = jsonToTorrentValues(parser);

                    String hash = (String) values.torrent.get(Constants.C_HASH_STRING);
                    if (removeObsolete) {
                        validHashStrings.add(hash);
                    }

                    int updated = database.update(
                        Constants.T_TORRENT, values.torrent, Constants.C_HASH_STRING + " = ?",
                        new String[] { hash });

                    if (updated < 1) {
                        database.insertWithOnConflict(Constants.T_TORRENT, null,
                            values.torrent, SQLiteDatabase.CONFLICT_REPLACE);
                    }

                    ContentValues profileValues = new ContentValues();
                    profileValues.put(Constants.C_HASH_STRING, hash);
{'fraction_non_alphanumeric': 0.08557682464940117, 'fraction_numerical': 0.0006141877367181902, 'mean_word_length': 2.2361709175223585, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, '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': '6817205', 'n_tokens_mistral': 2556, 'n_tokens_neox': 2418, 'n_words': 540}