package com.fsck.k9.service;


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

import org.apache.commons.io.output.DeferredFileOutputStream;
import org.apache.commons.io.output.ThresholdingOutputStream;


/**
 * This OutputStream is modelled after apache commons' {@link DeferredFileOutputStream},
 * but uses a {@link FileProviderInterface} instead of directly generating temporary files
 * itself.
 */
public class FileProviderDeferredFileOutputStream extends ThresholdingOutputStream {


    private ByteArrayOutputStream memoryOutputStream;
    private OutputStream currentOutputStream;
    private File outputFile;
    private final FileProviderInterface fileProviderInterface;


    public FileProviderDeferredFileOutputStream(int threshold, FileProviderInterface fileProviderInterface) {
        super(threshold);
        memoryOutputStream = new ByteArrayOutputStream();
        currentOutputStream = memoryOutputStream;
        this.fileProviderInterface = fileProviderInterface;
    }


    @Override
    protected OutputStream getStream() throws IOException {
        return currentOutputStream;
    }


    @Override
    protected void thresholdReached() throws IOException {
        outputFile = fileProviderInterface.createProvidedFile();
        FileOutputStream fos = new FileOutputStream(outputFile);
        memoryOutputStream.writeTo(fos);
        currentOutputStream = fos;
        memoryOutputStream = null;
    }

    public byte[] getData() {
        if (memoryOutputStream != null)
        {
            return memoryOutputStream.toByteArray();
        }
        return null;
    }

    public File getFile() {
        return outputFile;
    }

}

@@ -588,64 +588,8 @@
 m %7B%0A
-%0A%0A    private ByteArrayOutputStream memoryOutputStream;%0A
     
@@ -872,56 +872,225 @@
     
-memoryOutputStream = new ByteArrayOutputStream()
+this.fileProviderInterface = fileProviderInterface;%0A%0A        // scale it so we expand the ByteArrayOutputStream at most three times (assuming quadratic growth)%0A        int size = threshold %3C 1024 ? 256 : threshold / 4
 ;%0A  
@@ -1117,21 +1117,28 @@
 tream = 
-memor
+new ByteArra
 yOutputS
@@ -1146,68 +1146,14 @@
 ream
-;%0A        this.fileProviderInterface = fileProviderInterface
+(size)
 ;%0A  
@@ -1149,33 +1149,32 @@
 m(size);%0A    %7D%0A%0A
-%0A
     @Override%0A  
@@ -1274,16 +1274,130 @@
 %0A    %7D%0A%0A
+    private boolean isMemoryBacked() %7B%0A        return currentOutputStream instanceof ByteArrayOutputStream;%0A    %7D%0A
 %0A    @Ov
@@ -1470,16 +1470,20 @@
         
+if (
 outputFi
@@ -1489,51 +1489,135 @@
 ile 
+!
 = 
-fileProviderInterface.createProvidedFile(
+null) %7B%0A            throw new IllegalStateException(%22thresholdReached must not be called if we already have an output file!%22
 );%0A 
@@ -1627,174 +1627,439 @@
     
-FileOutputStream fos = new FileOutputStream(outputFile);%0A        memoryOutputStream.writeTo(fos);%0A        currentOutputStream = fos;%0A        memoryOutputStream = null
+%7D%0A        if (!isMemoryBacked()) %7B%0A            throw new IllegalStateException(%22currentOutputStream must be memory-based at this point!%22);%0A        %7D%0A        ByteArrayOutputStream memoryOutputStream = (ByteArrayOutputStream) currentOutputStream;%0A%0A        outputFile = fileProviderInterface.createProvidedFile();%0A        currentOutputStream = new FileOutputStream(outputFile);%0A%0A        memoryOutputStream.writeTo(currentOutputStream)
 ;%0A  
@@ -2109,35 +2109,128 @@
 if (
-m
+!isM
 emory
-OutputStream != null)
+Backed()) %7B%0A            throw new IllegalStateException(%22getData must only be called in memory-backed state!%22);
 %0A   
@@ -2234,22 +2234,18 @@
         
-%7B%0A    
+%7D%0A
         
@@ -2251,21 +2251,26 @@
  return 
-memor
+((ByteArra
 yOutputS
@@ -2274,16 +2274,38 @@
 utStream
+) currentOutputStream)
 .toByteA
@@ -2320,69 +2320,178 @@
     
+%7D%0A%0A
     
-%7D%0A        return null;%0A    %7D%0A%0A    public File getFile() %7B
+public File getFile() %7B%0A        if (isMemoryBacked()) %7B%0A            throw new IllegalStateException(%22getFile must only be called in file-backed state!%22);%0A        %7D
 %0A   

make FileProviderDeferredFileOutputStream fail faster