package jp.sourceforge.nicoro;

import android.os.Environment;
import android.test.AndroidTestCase;

import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class MultiRandomAccessFileTests extends AndroidTestCase {
    private static final String TEST_FILE_PATH =
        Environment.getExternalStorageDirectory().getAbsolutePath()
        + "/NicoRo_MultiRandomAccessFileTests.dat";
    private static final int TEST_FILE_SIZE = 1024 * 1024 * 1;
    private static final int TEST_FILE_BLOCK = 256;

    private File mTestFile = new File(TEST_FILE_PATH);
    private AbstractMultiRandomAccessFile mMultiRandomAccessFile;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
    }

    @Override
    protected void tearDown() throws Exception {
        try {
            if (mMultiRandomAccessFile != null) {
                mMultiRandomAccessFile.close();
            }
        } finally {
            mMultiRandomAccessFile = null;
            mTestFile.delete();
            super.tearDown();
        }
    }

    public void testFile() throws Exception {
        mMultiRandomAccessFile = new MultiRandomAccessFile(mTestFile, true);
        testCommon();
    }
    public void testMmap() throws Exception {
        mMultiRandomAccessFile = new MultiRandomAccessFileMmap(mTestFile, true);
        testCommon();
    }

    private void testCommon() throws Exception {
        assertNotNull(mMultiRandomAccessFile);
        mMultiRandomAccessFile.setLength(TEST_FILE_SIZE);

        CountDownLatch latch = new CountDownLatch(2);
        TestThread write = new TestThread(latch) {
            @Override
            protected void runImpl() throws Exception {
                AbstractMultiRandomAccessFile file = mMultiRandomAccessFile;
                byte[] buffer = new byte[TEST_FILE_BLOCK];
                for (int i = 0; i < buffer.length; ++i) {
                    buffer[i] = (byte) i;
                }
                for (int i = 0; i < TEST_FILE_SIZE / TEST_FILE_BLOCK; ++i) {
                    file.write(buffer, 0, TEST_FILE_BLOCK - 33);
                    file.write(buffer, TEST_FILE_BLOCK - 33, 33);
//                    file.write(buffer, 0, TEST_FILE_BLOCK);
                }
            }
        };
        TestThread read = new TestThread(latch) {
            @Override
            protected void runImpl() throws Exception {
                AbstractMultiRandomAccessFile file = mMultiRandomAccessFile;
                byte[] buffer = new byte[TEST_FILE_BLOCK];
                for (int i = 0; i < TEST_FILE_SIZE / TEST_FILE_BLOCK; ++i) {
                    for (int j = 0; j < buffer.length; ++j) {
                        buffer[j] = 0;
                    }
                    file.readFully(buffer);
                    for (int j = 0; j < buffer.length; ++j) {
                        // Stringの無駄な生成回避
                        if ((byte) j != buffer[j]) {
                            assertEquals("at 0x" + (i * TEST_FILE_BLOCK + j),
                                    (byte) j, buffer[j]);
                        }
                    }
                }
            }
        };
        write.start();
        read.start();
        assertTrue(latch.await(60, TimeUnit.SECONDS));

        write.throwIfFailed();
        read.throwIfFailed();
    }
}
