package org.emfjson.mongo.streams;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.URIConverter.Loadable;
import org.emfjson.jackson.module.EMFModule;
import org.emfjson.mongo.MongoHelper;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.util.JSON;

public class MongoInputStream extends InputStream implements Loadable {

	private final Map<?, ?> options;
	private final URI uri;

	public MongoInputStream(URI uri, Map<?, ?> options) {
		this.uri = uri;
		this.options = options;
	}

	@Override
	public void loadResource(Resource resource) throws IOException {
		final MongoClient client = MongoHelper.getClient(uri);
		final DB db = MongoHelper.getDB(client, uri);
		final DBCollection collection = MongoHelper.getCollection(db, uri);

		DBCursor cursor = collection.find(new BasicDBObject("_id", uri.segment(2)));

		if (!resource.getContents().isEmpty()) {
			resource.getContents().clear();
		}

		try {
			while (cursor.hasNext()) {
				DBObject dbObject = cursor.next();
				String data = JSON.serialize(dbObject);

				readJson(resource, data);
			}
		} finally {
			cursor.close();
		}
	}

	private void readJson(Resource resource, String data) throws IOException {
		final ObjectMapper mapper = new ObjectMapper();
		mapper.registerModule(new EMFModule(options));
		ObjectNode rootNode = null;
		try {
			rootNode = (ObjectNode) mapper.readTree(data);
		} catch (IOException e) {
			throw e;
		}

		final EObject result = mapper.readValue(rootNode.get("contents").traverse(), EObject.class);

		if (result != null) {
			resource.getContents().add(result);
		}
	}

	@Override
	public int read() throws IOException {
		return 0;
	}

}

@@ -40,79 +40,152 @@
 ort 
-java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java
+com.fasterxml.jackson.databind.JsonNode;%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0Aimport com.mongodb.*;%0Aimport com.mongodb
 .util.
-Map;%0A
+JSON;
 %0Aimp
@@ -225,46 +225,8 @@
 RI;%0A
-import org.eclipse.emf.ecore.EObject;%0A
 impo
@@ -353,388 +353,190 @@
 son.
-jackson.module.EMFModule;%0Aimport org.emfjson.mongo.MongoHelper;%0A%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0Aimport com.fasterxml.jackson.databind.node.ObjectNode;%0Aimport com.mongodb.BasicDBObject;%0Aimport com.mongodb.DB
+common.Options;%0Aimport org.emfjson.jackson.streaming.StreamReader;%0Aimport org.emfjson.mongo.MongoHelper
 ;%0A
+%0A
 import 
-com.mongodb.DBCollection;%0Aimport com.mongodb.DBCursor;%0Aimport com.mongodb.DBObject;%0Aimport com.mongodb.MongoClient;%0Aimport com.mongodb
+java.io.IOException;%0Aimport java.io.InputStream;%0Aimport java
 .util.
-JSON
+Map
 ;%0A%0Ap
@@ -1026,182 +1026,201 @@
 );%0A%0A
-%09%09DBCursor cursor = collection.find(new BasicDBObject(%22_id%22, uri.segment(2)));%0A%0A%09%09if (!resource.getContents().isEmpty()) %7B%0A%09%09%09resource.getContents().clear();%0A%09%09%7D%0A%0A%09%09try %7B%0A%09%09%09
+        if (!resource.getContents().isEmpty()) %7B%0A%09%09%09resource.getContents().clear();%0A%09%09%7D%0A%0A        try (DBCursor cursor = collection.find(new BasicDBObject(%22_id%22, uri.segment(2)))) %7B%0A            
 whil
@@ -1242,20 +1242,32 @@
 xt()) %7B%0A
-%09%09%09%09
+                
 DBObject
@@ -1293,20 +1293,32 @@
 next();%0A
-%09%09%09%09
+                
 String d
@@ -1354,12 +1354,24 @@
 );%0A%0A
-%09%09%09%09
+                
 read
@@ -1396,48 +1396,30 @@
 a);%0A
-%09%09%09%7D%0A%09%09%7D finally %7B%0A%09%09%09cursor.close();%0A%09%09
+            %7D%0A        
 %7D%0A%09%7D
@@ -1550,351 +1550,340 @@
 ();%0A
-%09%09mapper.registerModule(new EMFModule(options));%0A%09%09ObjectNode rootNode = null;%0A%09%09try %7B%0A%09%09%09rootNode = (ObjectNode) mapper.readTree(data);%0A%09%09%7D catch (IOException e) %7B%0A%09%09%09throw e;%0A%09%09%7D%0A%0A%09%09final EObject result = mapper.readValue(rootNode.get(%22contents%22).traverse(), EObject.class);%0A%0A%09%09if (result != null) %7B%0A%09%09%09resource.getContents().add(result);%0A%09%09
+        final JsonNode rootNode = mapper.readTree(data);%0A        final JsonNode contents = rootNode.has(%22contents%22) ? rootNode.get(%22contents%22) : null;%0A%0A        if (contents != null) %7B%0A            StreamReader reader = new StreamReader(Options.from(options).build());%0A            reader.parse(resource, contents.traverse());%0A        
 %7D%0A%09%7D

Use StreamReader instead of EMFModule since the latter cannot currently use the current resourceSet.