package com.yichiuan.moedict.data;

import android.content.Context;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Formatter;

import moe.Dictionary;
import moe.Index;
import moe.Word;
import timber.log.Timber;

public class MoeRepository {

    private static final int MOD_MASK = 0x3FF; // 0b1111111111
    private static final int BUFFER_SIZE = (int)(1024 * 1024 * 3.2); // 3.2MB

    private static final String MOE_INDEX_DATAPATH = "moe/index.bin";

    private Context context;

    private StringBuilder appendable = new StringBuilder();
    private Formatter formatter = new Formatter(appendable);

    private byte[] buffer;

    // Private constructor prevents instantiation from other classes
    MoeRepository(Context context) {
        this.context = context;
    }

    public Word getMoeWord(String word) {

        int firstWord = word.codePointAt(0);
        int mod = firstWord & MOD_MASK; // code point % 1024

        appendable.setLength(0);
        String dataPath = formatter.format("moe/%d.bin", mod).toString();

        Dictionary dict = Dictionary.getRootAsDictionary(loadData(dataPath));
        return dict.wordsByKey(word);
    }

    public Index getIndex() {
        return Index.getRootAsIndex(loadData(MOE_INDEX_DATAPATH));
    }

    private ByteBuffer loadData(String dataPath) {

        int readSize = 0;
        try {
            final InputStream is = context.getAssets().open(dataPath);

            int size = is.available();

            if (buffer == null) {
                buffer = new byte[BUFFER_SIZE];
            }
            readSize = is.read(buffer, 0, size);

            is.close();

        } catch (IOException e) {
            Timber.e(e);
        }

        return ByteBuffer.wrap(buffer, 0, readSize);
    }
}
@@ -60,16 +60,103 @@
 Context;
+%0Aimport android.support.annotation.NonNull;%0Aimport android.support.annotation.Nullable;
 %0A%0Aimport
@@ -507,17 +507,17 @@
 4 * 
-3
+1
 .2); // 
 3.2M
@@ -516,11 +516,12 @@
  // 
-3
+1
 .2
+ 
 MB%0A%0A
@@ -762,17 +762,58 @@
  byte%5B%5D 
-b
+dictBuffer;%0A%0A    private ByteBuffer indexB
 uffer;%0A%0A
@@ -1273,24 +1273,28 @@
 ionary(loadD
+ictD
 ata(dataPath
@@ -1384,64 +1384,355 @@
     
-return Index.getRootAsIndex(loadData(MOE_INDEX_DATAPATH)
+if (indexBuffer == null) %7B%0A            indexBuffer = loadData(MOE_INDEX_DATAPATH, null);%0A        %7D%0A        return Index.getRootAsIndex(indexBuffer);%0A    %7D%0A%0A    private ByteBuffer loadDictData(String dataPath) %7B%0A        if (dictBuffer == null) %7B%0A            dictBuffer = new byte%5BBUFFER_SIZE%5D;%0A        %7D%0A        return loadData(dataPath, dictBuffer
 );%0A 
@@ -1765,24 +1765,33 @@
 er loadData(
+@NonNull 
 String dataP
@@ -1789,24 +1789,49 @@
 ing dataPath
+, @Nullable byte%5B%5D buffer
 ) %7B%0A%0A       
@@ -1849,16 +1849,53 @@
 ze = 0;%0A
+        byte%5B%5D readBuffer = buffer;%0A%0A
         
@@ -2028,17 +2028,21 @@
     if (
-b
+readB
 uffer ==
@@ -2038,32 +2038,60 @@
 adBuffer == null
+ %7C%7C readBuffer.length %3C size
 ) %7B%0A            
@@ -2094,17 +2094,21 @@
         
-b
+readB
 uffer = 
@@ -2112,35 +2112,28 @@
  = new byte%5B
-BUFFER_SIZE
+size
 %5D;%0A         
@@ -2168,17 +2168,21 @@
 is.read(
-b
+readB
 uffer, 0
@@ -2317,17 +2317,21 @@
 er.wrap(
-b
+readB
 uffer, 0

Load the index data one time only.