/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 com.android.server.net;

import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DelayedDiskWrite {
    private HandlerThread mDiskWriteHandlerThread;
    private Handler mDiskWriteHandler;
    /* Tracks multiple writes on the same thread */
    private int mWriteSequence = 0;
    private final String TAG = "DelayedDiskWrite";

    public interface Writer {
        public void onWriteCalled(DataOutputStream out) throws IOException;
    }

    public void write(final String filePath, final Writer w) {
        write(filePath, w, true);
    }

    public void write(final String filePath, final Writer w, final boolean open) {
        if (TextUtils.isEmpty(filePath)) {
            throw new IllegalArgumentException("empty file path");
        }

        /* Do a delayed write to disk on a separate handler thread */
        synchronized (this) {
            if (++mWriteSequence == 1) {
                mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread");
                mDiskWriteHandlerThread.start();
                mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper());
            }
        }

        mDiskWriteHandler.post(new Runnable() {
            @Override
            public void run() {
                doWrite(filePath, w, open);
            }
        });
    }

    private void doWrite(String filePath, Writer w, boolean open) {
        DataOutputStream out = null;
        try {
            if (open) {
                out = new DataOutputStream(new BufferedOutputStream(
                        new FileOutputStream(filePath)));
            }
            w.onWriteCalled(out);
        } catch (IOException e) {
            loge("Error writing data file " + filePath);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {}
            }

            // Quit if no more writes sent
            synchronized (this) {
                if (--mWriteSequence == 0) {
                    mDiskWriteHandler.getLooper().quit();
                    mDiskWriteHandler = null;
                    mDiskWriteHandlerThread = null;
                }
            }
        }
    }

    private void loge(String s) {
        Log.e(TAG, s);
    }
}

