package com.github.davidmoten.rtree.fbs;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.junit.Test;

import com.github.davidmoten.rtree.GreekEarthquakes;
import com.github.davidmoten.rtree.Leaf;
import com.github.davidmoten.rtree.Node;
import com.github.davidmoten.rtree.NonLeaf;
import com.github.davidmoten.rtree.RTree;
import com.github.davidmoten.rtree.flatbuffers.Box_;
import com.github.davidmoten.rtree.flatbuffers.Context_;
import com.github.davidmoten.rtree.flatbuffers.Node_;
import com.github.davidmoten.rtree.flatbuffers.Tree_;
import com.github.davidmoten.rtree.geometry.Geometry;
import com.github.davidmoten.rtree.geometry.Point;
import com.github.davidmoten.rtree.geometry.Rectangle;
import com.google.flatbuffers.FlatBufferBuilder;

import rx.functions.Func1;

public class FlatBuffersSerializer {

    public <T, S extends Geometry> void serialize(RTree<T, S> tree, Func1<T, byte[]> serializer,
            OutputStream os) throws IOException {
        FlatBufferBuilder builder = new FlatBufferBuilder();
        int n = addNode(tree.root().get(), builder, serializer);

        Rectangle mbb = tree.root().get().geometry().mbr();
        int b = Box_.createBox_(builder, mbb.x1(), mbb.y1(), mbb.x2(), mbb.y2());
        Context_.startContext_(builder);
        Context_.addBounds(builder, b);
        Context_.addMaxChildren(builder, tree.context().maxChildren());
        Context_.addMinChildren(builder, tree.context().minChildren());
        int c = Context_.endContext_(builder);

        int t = Tree_.createTree_(builder, c, n);
        Tree_.finishTree_Buffer(builder, t);
        os.write(builder.dataBuffer().array());
    }

    private static <T, S extends Geometry> int addNode(Node<T, S> node, FlatBufferBuilder builder,
            Func1<T, byte[]> serializer) {
        if (node instanceof Leaf) {
            Leaf<T, S> leaf = (Leaf<T, S>) node;
            return FlatBuffersHelper.addEntries(leaf.entries(), builder, serializer);
        } else {
            NonLeaf<T, S> nonLeaf = (NonLeaf<T, S>) node;
            int[] nodes = new int[nonLeaf.count()];
            for (int i = 0; i < nonLeaf.count(); i++) {
                Node<T, S> child = nonLeaf.children().get(i);
                nodes[i] = addNode(child, builder, serializer);
            }
            int ch = Node_.createChildrenVector(builder, nodes);
            Node_.startNode_(builder);
            Node_.addChildren(builder, ch);
            Rectangle mbb = nonLeaf.geometry().mbr();
            int b = Box_.createBox_(builder, mbb.x1(), mbb.y1(), mbb.x2(), mbb.y2());
            Node_.addMbb(builder, b);
            return Node_.endNode_(builder);
        }
    }

    public <T, S extends Geometry> RTree<T, S> deserialize(InputStream is) {
        throw new UnsupportedOperationException("not implemented yet");
    }

    @Test
    public void testSerialize() throws IOException {
        RTree<Object, Point> tree = RTree.star().create();
        tree = tree.add(GreekEarthquakes.entries()).last().toBlocking().single();
        FileOutputStream os = new FileOutputStream(new File("target/file"));
        new FlatBuffersSerializer().serialize(tree, new Func1<Object, byte[]>() {
            @Override
            public byte[] call(Object o) {
                return "boo".getBytes();
            }
        }, os);
        os.close();
    }

}

@@ -3044,16 +3044,31 @@
 .star().
+maxChildren(4).
 create()
@@ -3065,24 +3065,24 @@
 ).create();%0A
-
         tree
@@ -3147,24 +3147,116 @@
 ).single();%0A
+        long t = System.currentTimeMillis();%0A        File output = new File(%22target/file%22);%0A
         File
@@ -3294,39 +3294,22 @@
 tStream(
-new File(%22target/file%22)
+output
 );%0A     
@@ -3517,24 +3517,24 @@
     %7D, os);%0A
-
         os.c
@@ -3537,21 +3537,157 @@
 os.close();%0A
+        System.out.println(%22written in %22 + (System.currentTimeMillis() - t) + %22ms, %22 + %22file size=%22%0A                + output.length());%0A
     %7D%0A%0A%7D%0A

add serialize to flatbuffers test