// Path: src/main/java/de/fhg/igd/mongomvcc/VCounter.java
// public interface VCounter {
// 	/**
// 	 * A thread safe method to get the next unique id
// 	 * @return a unique id
// 	 */
// 	public long getNextId();
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/VCursor.java
// public interface VCursor extends Iterable<Map<String, Object>> {
// 	/**
// 	 * @return the number of database objects this cursor points to
// 	 */
// 	int size();
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/VLargeCollection.java
// public interface VLargeCollection extends VCollection {
// 	//nothing to add yet
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/helper/Filter.java
// public interface Filter<T> {
// 	/**
// 	 * Checks if the given element passes the filter
// 	 * @param t the element
// 	 * @return true if the element passes the filter, false otherwise
// 	 */
// 	boolean filter(T t);
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/helper/TransformingIterator.java
// public abstract class TransformingIterator<I, O> implements Iterator<O> {
// 	/**
// 	 * The wrapped iterator
// 	 */
// 	private final Iterator<I> _delegate;
// 	
// 	/**
// 	 * Constructs a new transforming iterator
// 	 * @param delegate the iterator to wrap
// 	 */
// 	public TransformingIterator(Iterator<I> delegate) {
// 		_delegate = delegate;
// 	}
// 	
// 	@Override
// 	public boolean hasNext() {
// 		return _delegate.hasNext();
// 	}
// 
// 	@Override
// 	public O next() {
// 		return transform(_delegate.next());
// 	}
// 	
// 	/**
// 	 * Transforms an element
// 	 * @param input the element
// 	 * @return the transformed element
// 	 */
// 	abstract protected O transform(I input);
// 
// 	@Override
// 	public void remove() {
// 		_delegate.remove();
// 	}
// }


import de.fhg.igd.mongomvcc.helper.Filter;
import de.fhg.igd.mongomvcc.helper.TransformingIterator;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSInputFile;
import de.fhg.igd.mongomvcc.VCounter;
import de.fhg.igd.mongomvcc.VCursor;
import de.fhg.igd.mongomvcc.VLargeCollection;
	 * @param delegate the actual MongoDB collection
	 * @param gridFS the MongoDB GridFS storing binary data
	 * @param branch the branch currently checked out
	 * @param counter a counter to generate unique IDs
	 * @param accessStrategy the strategy that should be used to access large objects
	 */
	public MongoDBVLargeCollection(DBCollection delegate, GridFS gridFS,
			MongoDBVBranch branch, VCounter counter, AccessStrategy accessStrategy) {
		super(delegate, branch, counter);
		_gridFS = gridFS;
		_accessStrategy = accessStrategy;
	}

	@Override
	public void insert(Map<String, Object> obj) {
		DefaultConvertStrategy cs = new DefaultConvertStrategy(_gridFS, getCounter());
		_accessStrategy.setConvertStrategy(cs);
		_accessStrategy.onInsert(obj);
		
		//save original object
		super.insert(obj);
		
		//save GridFS files
		for (GridFSInputFile file : cs.getConvertedFiles()) {
			file.put(PARENT, obj.get(OID));
			file.save();
		}
	}
	
	@Override
// Path: src/main/java/de/fhg/igd/mongomvcc/VCounter.java
// public interface VCounter {
// 	/**
// 	 * A thread safe method to get the next unique id
// 	 * @return a unique id
// 	 */
// 	public long getNextId();
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/VCursor.java
// public interface VCursor extends Iterable<Map<String, Object>> {
// 	/**
// 	 * @return the number of database objects this cursor points to
// 	 */
// 	int size();
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/VLargeCollection.java
// public interface VLargeCollection extends VCollection {
// 	//nothing to add yet
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/helper/Filter.java
// public interface Filter<T> {
// 	/**
// 	 * Checks if the given element passes the filter
// 	 * @param t the element
// 	 * @return true if the element passes the filter, false otherwise
// 	 */
// 	boolean filter(T t);
// }
// 
// Path: src/main/java/de/fhg/igd/mongomvcc/helper/TransformingIterator.java
// public abstract class TransformingIterator<I, O> implements Iterator<O> {
// 	/**
// 	 * The wrapped iterator
// 	 */
// 	private final Iterator<I> _delegate;
// 	
// 	/**
// 	 * Constructs a new transforming iterator
// 	 * @param delegate the iterator to wrap
// 	 */
// 	public TransformingIterator(Iterator<I> delegate) {
// 		_delegate = delegate;
// 	}
// 	
// 	@Override
// 	public boolean hasNext() {
// 		return _delegate.hasNext();
// 	}
// 
// 	@Override
// 	public O next() {
// 		return transform(_delegate.next());
// 	}
// 	
// 	/**
// 	 * Transforms an element
// 	 * @param input the element
// 	 * @return the transformed element
// 	 */
// 	abstract protected O transform(I input);
// 
// 	@Override
// 	public void remove() {
// 		_delegate.remove();
// 	}
// }


// Path: src/main/java/de/fhg/igd/mongomvcc/impl/MongoDBVLargeCollection.java
import de.fhg.igd.mongomvcc.helper.Filter;
import de.fhg.igd.mongomvcc.helper.TransformingIterator;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSInputFile;
import de.fhg.igd.mongomvcc.VCounter;
import de.fhg.igd.mongomvcc.VCursor;
import de.fhg.igd.mongomvcc.VLargeCollection;

	 * @param delegate the actual MongoDB collection
	 * @param gridFS the MongoDB GridFS storing binary data
	 * @param branch the branch currently checked out
	 * @param counter a counter to generate unique IDs
	 * @param accessStrategy the strategy that should be used to access large objects
	 */
	public MongoDBVLargeCollection(DBCollection delegate, GridFS gridFS,
			MongoDBVBranch branch, VCounter counter, AccessStrategy accessStrategy) {
		super(delegate, branch, counter);
		_gridFS = gridFS;
		_accessStrategy = accessStrategy;
	}

	@Override
	public void insert(Map<String, Object> obj) {
		DefaultConvertStrategy cs = new DefaultConvertStrategy(_gridFS, getCounter());
		_accessStrategy.setConvertStrategy(cs);
		_accessStrategy.onInsert(obj);
		
		//save original object
		super.insert(obj);
		
		//save GridFS files
		for (GridFSInputFile file : cs.getConvertedFiles()) {
			file.put(PARENT, obj.get(OID));
			file.save();
		}
	}
	
	@Override
	protected VCursor createCursor(DBCursor delegate, Filter<DBObject> filter) {