/* UtilLib - Copyright (c) 2016-2020 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.function.Consumer;
import net.mapeadores.util.exceptions.NestedIOException;


/**
 *
 * @author Vincent Calame
 */
public class TempStorageAppendable implements Appendable, Consumer<Writer> {

    private final static int MAX_LENGTH = 1048576;
    private StringBuilder memoryStorage = new StringBuilder(MAX_LENGTH + 1024);
    private BufferedWriter fileStorage;
    private File tempFile;
    private boolean onMemory = true;
    private Appendable currentAppendable = memoryStorage;

    public TempStorageAppendable() {

    }

    @Override
    public Appendable append(CharSequence cs) throws IOException {
        testMemory();
        currentAppendable.append(cs);
        return currentAppendable;
    }

    @Override
    public Appendable append(CharSequence cs, int start, int end) throws IOException {
        testMemory();
        currentAppendable.append(cs, start, end);
        return currentAppendable;
    }

    @Override
    public Appendable append(char c) throws IOException {
        testMemory();
        currentAppendable.append(c);
        return currentAppendable;
    }

    private void testMemory() throws IOException {
        if ((onMemory) && (memoryStorage.length() > MAX_LENGTH)) {
            tempFile = File.createTempFile("tempstorage", null);
            Writer writer = new OutputStreamWriter(new FileOutputStream(tempFile), "UTF-8");
            writer.append(memoryStorage);
            memoryStorage = null;
            onMemory = false;
            fileStorage = new BufferedWriter(writer);
            currentAppendable = fileStorage;
        }
    }

    @Override
    public void accept(Writer destination) {
        try {
            flush(destination);
        } catch (IOException ioe) {
            throw new NestedIOException(ioe);
        }
    }

    public void flush(Writer destination) throws IOException {
        if (onMemory) {
            destination.append(memoryStorage);
            memoryStorage = null;
        } else {
            fileStorage.flush();
            fileStorage.close();
            try (Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(tempFile), "UTF-8"))) {
                IOUtils.copy(reader, destination);
            }
            tempFile.delete();
        }
    }

}
