<commit_before>package org.commcare.xml;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.crypto.Cipher;

import net.sqlcipher.database.SQLiteDatabase;

import org.commcare.android.database.SqlStorage;
import org.commcare.android.database.UserStorageClosedException;
import org.commcare.android.database.user.models.ACase;
import org.commcare.android.database.user.models.CaseIndexTable;
import org.commcare.android.database.user.models.EntityStorageCache;
import org.commcare.android.javarosa.AndroidLogger;
import org.commcare.android.logic.GlobalConstants;
import org.commcare.android.net.HttpRequestGenerator;
import org.commcare.android.references.JavaHttpReference;
import org.commcare.android.util.AndroidStreamUtil;
import org.commcare.android.util.FileUtil;
import org.commcare.android.util.SessionUnavailableException;
import org.commcare.cases.model.Case;
import org.commcare.dalvik.application.CommCareApplication;
import org.javarosa.core.reference.InvalidReferenceException;
import org.javarosa.core.reference.Reference;
import org.javarosa.core.reference.ReferenceManager;
import org.javarosa.core.services.Logger;
import org.javarosa.core.services.storage.IStorageUtilityIndexed;
import org.javarosa.core.util.PropertyUtils;
import org.kxml2.io.KXmlParser;

import android.net.ParseException;
import android.net.Uri;
import android.util.Pair;

/**
 * @author ctsims
 *
 */
public class AndroidCaseXmlParser extends CaseXmlParser {
    Cipher attachmentCipher;
    Cipher userCipher;
    File folder;
    boolean processAttachments = true;
    HttpRequestGenerator generator;
    EntityStorageCache mEntityCache;
    CaseIndexTable mCaseIndexTable;
    
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage, EntityStorageCache entityCache, CaseIndexTable indexTable) {
        super(parser, storage);
        mEntityCache = entityCache;
        mCaseIndexTable = indexTable;
    }    
    
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage) {
        this(parser, storage, new EntityStorageCache("case"), new CaseIndexTable());
    }
    
    //TODO: Sync the following two constructors!
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage, Cipher attachmentCipher, Cipher userCipher, File folder) {
        this(parser, storage);
        this.attachmentCipher = attachmentCipher;
        this.userCipher = userCipher;
        this.folder = folder;
        processAttachments = true;
    }

    public AndroidCaseXmlParser(KXmlParser parser, int[] tallies, boolean b, SqlStorage<ACase> storage, HttpRequestGenerator generator) {
        super(parser, tallies, b, storage);
        this.generator = generator;
        mEntityCache = new EntityStorageCache("case");
        mCaseIndexTable = new CaseIndexTable();
    }
    
    /*
     * (non-Javadoc)
     * @see org.commcare.xml.CaseXmlParser#removeAttachment(org.commcare.cases.model.Case, java.lang.String)
     */
    @Override
    protected void removeAttachment(Case caseForBlock, String attachmentName) {
        if(!processAttachments) { return;}
        
        //TODO: All of this code should really be somewhere else, too, since we also need to remove attachments on
        //purge.
        String source = caseForBlock.getAttachmentSource(attachmentName);
        
        //TODO: Handle remote reference download?
        if(source == null) { return;}

        //Handle these cases better later.
        try {
            ReferenceManager._().DeriveReference(source).remove();
        } catch (InvalidReferenceException | IOException e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public void commit(Case parsed) throws IOException {
        SQLiteDatabase db;
        try {
            db = CommCareApplication._().getUserDbHandle();
        } catch (SessionUnavailableException e) {
            throw new UserStorageClosedException("User database closed while parsing");
        }
        db.beginTransaction();
        try {
            super.commit(parsed);
            mEntityCache.invalidateCache(String.valueOf(parsed.getID()));
            mCaseIndexTable.clearCaseIndices(parsed);
            mCaseIndexTable.indexCase(parsed);
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
    }

    /*
     * (non-Javadoc)
     * @see org.commcare.xml.CaseXmlParser#processAttachment(java.lang.String, java.lang.String, java.lang.String, org.kxml2.io.KXmlParser)
     */
    @Override
    protected String processAttachment(String src, String from, String name, KXmlParser parser) {
        if(!processAttachments) { return null;}
        <commit_msg>Fixed missing storage abstraction for case processing unit tests<commit_after>package org.commcare.xml;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.crypto.Cipher;

import net.sqlcipher.database.SQLiteDatabase;

import org.commcare.android.database.SqlStorage;
import org.commcare.android.database.UserStorageClosedException;
import org.commcare.android.database.user.models.ACase;
import org.commcare.android.database.user.models.CaseIndexTable;
import org.commcare.android.database.user.models.EntityStorageCache;
import org.commcare.android.javarosa.AndroidLogger;
import org.commcare.android.logic.GlobalConstants;
import org.commcare.android.net.HttpRequestGenerator;
import org.commcare.android.references.JavaHttpReference;
import org.commcare.android.util.AndroidStreamUtil;
import org.commcare.android.util.FileUtil;
import org.commcare.android.util.SessionUnavailableException;
import org.commcare.cases.model.Case;
import org.commcare.dalvik.application.CommCareApplication;
import org.javarosa.core.reference.InvalidReferenceException;
import org.javarosa.core.reference.Reference;
import org.javarosa.core.reference.ReferenceManager;
import org.javarosa.core.services.Logger;
import org.javarosa.core.services.storage.IStorageUtilityIndexed;
import org.javarosa.core.util.PropertyUtils;
import org.kxml2.io.KXmlParser;

import android.net.ParseException;
import android.net.Uri;
import android.util.Pair;

/**
 * @author ctsims
 *
 */
public class AndroidCaseXmlParser extends CaseXmlParser {
    Cipher attachmentCipher;
    Cipher userCipher;
    File folder;
    boolean processAttachments = true;
    HttpRequestGenerator generator;
    EntityStorageCache mEntityCache;
    CaseIndexTable mCaseIndexTable;
    
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage, EntityStorageCache entityCache, CaseIndexTable indexTable) {
        super(parser, storage);
        mEntityCache = entityCache;
        mCaseIndexTable = indexTable;
    }    
    
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage) {
        this(parser, storage, new EntityStorageCache("case"), new CaseIndexTable());
    }
    
    //TODO: Sync the following two constructors!
    public AndroidCaseXmlParser(KXmlParser parser, IStorageUtilityIndexed storage, Cipher attachmentCipher, Cipher userCipher, File folder) {
        this(parser, storage);
        this.attachmentCipher = attachmentCipher;
        this.userCipher = userCipher;
        this.folder = folder;
        processAttachments = true;
    }

    public AndroidCaseXmlParser(KXmlParser parser, int[] tallies, boolean b, SqlStorage<ACase> storage, HttpRequestGenerator generator) {
        super(parser, tallies, b, storage);
        this.generator = generator;
        mEntityCache = new EntityStorageCache("case");
        mCaseIndexTable = new CaseIndexTable();
    }
    
    /*
     * (non-Javadoc)
     * @see org.commcare.xml.CaseXmlParser#removeAttachment(org.commcare.cases.model.Case, java.lang.String)
     */
    @Override
    protected void removeAttachment(Case caseForBlock, String attachmentName) {
        if(!processAttachments) { return;}
        
        //TODO: All of this code should really be somewhere else, too, since we also need to remove attachments on
        //purge.
        String source = caseForBlock.getAttachmentSource(attachmentName);
        
        //TODO: Handle remote reference download?
        if(source == null) { return;}

        //Handle these cases better later.
        try {
            ReferenceManager._().DeriveReference(source).remove();
        } catch (InvalidReferenceException | IOException e) {
            e.printStackTrace();
        }
    }

    protected SQLiteDatabase getDbHandle() throws SessionUnavailableException {
        return CommCareApplication._().getUserDbHandle();
    }

    @Override
    public void commit(Case parsed) throws IOException {
        SQLiteDatabase db;
        try {
            db = getDbHandle();
        } catch (SessionUnavailableException e) {
            throw new UserStorageClosedException("User database closed while parsing");
        }
        db.beginTransaction();
        try {
            super.commit(parsed);
            mEntityCache.invalidateCache(String.valueOf(parsed.getID()));
            mCaseIndexTable.clearCaseIndices(parsed);
            mCaseIndexTable.indexCase(parsed);
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
    }

    /*
     * (non-Javadoc)
     * @see org.commcare.xml.CaseXmlParser#processAttachment(java.lang.String, java.lang.String, java.lang.String, org.kxml2.io.KXmlParser)
     */
    @Override
    protected String processAttachment(String src, String from, String name, KXmlParser parser) {
        if(!processAttachments) { return null;}
        
{'fraction_non_alphanumeric': 0.09086210461029563, 'fraction_numerical': 0.0004134794293983874, 'mean_word_length': 3.468822170900693, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2553226', 'n_tokens_mistral': 2637, 'n_tokens_neox': 2634, 'n_words': 545}