/*
 *  Copyright 2012-2013 Brian S O'Neill
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.cojen.tupl;

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

import java.util.HashMap;
import java.util.Map;

import org.cojen.tupl.io.CauseCloseable;
import org.cojen.tupl.io.FileFactory;

/**
 * 
 *
 * @author Brian S O'Neill
 */
final class TempFileManager implements CauseCloseable, Checkpointer.Shutdown {
    private File mBaseFile;
    private final FileFactory mFileFactory;
    private long mCount;
    private Map<File, CauseCloseable> mFiles;

    private Throwable mCause;

    /**
     * @param factory optional
     */
    TempFileManager(File baseFile, FileFactory factory) throws IOException {
        mBaseFile = baseFile;
        mFileFactory = factory;

        // Delete old files.
        Utils.deleteNumberedFiles(baseFile, ".temp.");
    }

    File createTempFile() throws IOException {
        while (true) {
            File file;
            synchronized (this) {
                if (mBaseFile == null) {
                    throw new IOException("Shutting down", mCause);
                }
                file = new File(mBaseFile.getPath() + ".temp." + (mCount++));
                if (mFiles == null) {
                    mFiles = new HashMap<>(4);
                }
                if (mFiles.containsKey(file)) {
                    continue;
                }
                mFiles.put(file, null);
            }

            // Note: File.deleteOnExit should never be used, since it leaks memory.

            if (mFileFactory == null) {
                if (file.createNewFile()) {
                    return file;
                }
            } else if (mFileFactory.createFile(file)) {
                return file;
            }

            synchronized (this) {
                mFiles.remove(file);
            }
        }
    }

    synchronized void register(File file, CauseCloseable c) throws IOException {
        if (mFiles == null || !mFiles.containsKey(file)) {
            if (mBaseFile == null) {
                throw new IOException("Shutting down", mCause);
            }
            return;
        }
        if (mFiles.get(file) != null) {
            // Only one registration allowed.
            throw new IllegalStateException();
        }
        mFiles.put(file, c);
    }

    void deleteTempFile(File file) {
        CauseCloseable c;
        synchronized (this) {
            if (mFiles == null || !mFiles.containsKey(file)) {
                return;
            }
            c = mFiles.remove(file);
        }
        Utils.closeQuietly(null, c);
        file.delete();
    }

    @Override
    public void close() {
        close(null);
    }

    @Override
    public void close(Throwable cause) {
        Map<File, CauseCloseable> files;
        synchronized (this) {
            mBaseFile = null;
            if (cause != null) {
                mCause = cause;
            }
            if (mFiles == null) {
                files = null;
            } else {
                files = new HashMap<>(mFiles);
                mFiles = null;
            }
        }

        if (files != null) {
            for (CauseCloseable c : files.values()) {
                Utils.closeQuietly(null, c, cause);
            }
            for (File f : files.keySet()) {
                f.delete();
            }
        }
    }

    @Override
    public void shutdown() {
        close();
    }
}

@@ -633,16 +633,42 @@
 .tupl;%0A%0A
+import java.io.Closeable;%0A
 import j
@@ -676,24 +676,24 @@
 va.io.File;%0A
-
 import java.
@@ -1070,37 +1070,32 @@
 ivate Map%3CFile, 
-Cause
 Closeable%3E mFile
@@ -2411,24 +2411,134 @@
    %7D%0A    %7D%0A%0A
+    /**%0A     * Register object to close when file is deleted. Can be CauseCloseable to receive cause.%0A     */%0A
     synchron
@@ -2563,29 +2563,24 @@
 (File file, 
-Cause
 Closeable c)
@@ -3029,21 +3029,16 @@
         
-Cause
 Closeabl
@@ -3428,21 +3428,16 @@
 p%3CFile, 
-Cause
 Closeabl
@@ -3794,32 +3794,32 @@
 iles != null) %7B%0A
+
             for 
@@ -3819,21 +3819,16 @@
    for (
-Cause
 Closeabl

Remove restriction on temp file registration.