package de.bwaldvogel.mongo.backend.projection;

import de.bwaldvogel.mongo.backend.Utils;
import de.bwaldvogel.mongo.bson.Document;

public class Projection {

    public static Document projectDocument(Document document, Document fields, String idField) {

        if (document == null) {
            return null;
        }

        Document newDocument = new Document();

        // implicitly add _id if not mentioned
        // http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/#return-the-specified-fields-and-the-id-field-only
        if (!fields.containsKey(idField)) {
            newDocument.put(idField, document.get(idField));
        }

        if (onlyExclusions(fields)) {
            newDocument.putAll(document);
            for (String excludedField : fields.keySet()) {
                newDocument.remove(excludedField);
            }
        } else {
            for (String key : fields.keySet()) {
                if (Utils.isTrue(fields.get(key))) {
                    projectField(document, newDocument, key);
                }
            }
        }

        return newDocument;
    }

    private static boolean onlyExclusions(Document fields) {
        for (String key : fields.keySet()) {
            if (Utils.isTrue(fields.get(key))) {
                return false;
            }
        }
        return true;
    }

    private static void projectField(Document document, Document newDocument, String key) {

        if (document == null) {
            return;
        }

        int dotPos = key.indexOf('.');
        if (dotPos > 0) {
            String mainKey = key.substring(0, dotPos);
            String subKey = key.substring(dotPos + 1);

            Object object = document.get(mainKey);
            // do not project the subdocument if it is not of type Document
            if (object instanceof Document) {
                if (!newDocument.containsKey(mainKey)) {
                    newDocument.put(mainKey, new Document());
                }
                projectField((Document) object, (Document) newDocument.get(mainKey), subKey);
            }
        } else {
            newDocument.put(key, document.get(key));
        }
    }
}

@@ -42,16 +42,45 @@
 ction;%0A%0A
+import java.util.Map.Entry;%0A%0A
 import d
@@ -113,16 +113,16 @@
 .Utils;%0A
-
 import d
@@ -930,33 +930,50 @@
        for (
-String ke
+Entry%3CString, Object%3E entr
 y : fields.k
@@ -963,34 +963,36 @@
  entry : fields.
-k
 e
+ntr
 ySet()) %7B%0A      
@@ -977,32 +977,126 @@
 s.entrySet()) %7B%0A
+                String key = entry.getKey();%0A                Object value = entry.getValue();%0A
                 
@@ -1108,39 +1108,29 @@
 tils.isTrue(
-fields.get(key)
+value
 )) %7B%0A       
@@ -1595,72 +1595,8 @@
 ) %7B%0A
-%0A        if (document == null) %7B%0A            return;%0A        %7D%0A%0A
     
@@ -1960,83 +1960,68 @@
     
-if (!newDocument.containsKey(mainKey)) %7B%0A                    newDocument.pu
+Document subDocument = (Document) newDocument.computeIfAbsen
 t(ma
@@ -2026,16 +2026,21 @@
 mainKey,
+ k -%3E
  new Doc
@@ -2049,34 +2049,16 @@
 ent());%0A
-                %7D%0A
         
@@ -2101,43 +2101,19 @@
 ct, 
-(Document) newDocument.get(mainKey)
+subDocument
 , su

Simplify projection