/*
 * Copyright 2012-2013 inBloom, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.slc.sli.dal.convert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slc.sli.common.util.uuid.UUIDGeneratorStrategy;
import org.slc.sli.domain.Entity;
import org.slc.sli.domain.MongoEntity;
import org.slc.sli.validation.schema.INaturalKeyExtractor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * Generic superdoc converter for most basic operations
 */
@Component
public class GenericSuperdocConverter {
	
    @Autowired
    @Qualifier("deterministicUUIDGeneratorStrategy")
    UUIDGeneratorStrategy uuidGeneratorStrategy;
    
    @Autowired
    INaturalKeyExtractor naturalKeyExtractor; 
    
    /*
     *  Move subdocs from embedded data to superdoc's body
     */
    protected Entity subdocsToBody(Entity parent, String subentityType, List<String> removeFields) {
        if (parent.getEmbeddedData() == null || parent.getEmbeddedData().isEmpty()) {
            return parent;
        }

        List<Entity> subdocs = parent.getEmbeddedData().remove(subentityType);
        if (subdocs == null || subdocs.isEmpty()) {
            return parent;
        }

        List<Map<String, Object>> subdocBody = new ArrayList<Map<String, Object>>();
        for (Entity e : subdocs) {
            for (String field : removeFields) {
                e.getBody().remove(field);
            }
            subdocBody.add(e.getBody());
        }
        parent.getBody().put(subentityType, subdocBody);

        return parent;
    } 

    /*
     * Move subdocs from superdoc's body to their own inside embedded data
     */
    protected Entity bodyToSubdocs(Entity parent, String subentityType, String parentKey) {
        if (parent.getBody().get(subentityType) != null) {
            List<Entity> subdocs = new ArrayList<Entity>();
            
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> subdocInBody = (List<Map<String, Object>>) parent.getBody().get(subentityType);
            for (Map<String, Object> inbodyDoc : subdocInBody) {
                inbodyDoc.put(parentKey, generateSuperdocDid(parent));
                MongoEntity subdoc = new MongoEntity(subentityType, null, inbodyDoc, null);
                subdocs.add(subdoc);
            }

            if (!subdocs.isEmpty()) {
                parent.getEmbeddedData().put(subentityType, subdocs);
                parent.getBody().remove(subentityType);
            }
        }

        return parent;
    }

    /**
     * calculates the Determinsitic ID of this entity
     * @param entity
     * @return
     */
    protected String generateSuperdocDid(Entity entity) {
        if (entity instanceof MongoEntity) {
            return ((MongoEntity) entity).generateDid(uuidGeneratorStrategy, naturalKeyExtractor);
        } else {
            MongoEntity wrapper = new MongoEntity(entity.getType(), null, entity.getBody(), entity.getMetaData());
            return wrapper.generateDid(uuidGeneratorStrategy, naturalKeyExtractor);
        }
    }
}

@@ -1147,16 +1147,88 @@
 rations%0A
+ * %0A * @author Yang Cao ycao@wgen.net%0A * @author Dong Liu dliu@wgen.net%0A
  */%0A@Com
@@ -1278,9 +1278,8 @@
 r %7B%0A
-%09
 %0A   
@@ -1457,17 +1457,16 @@
 tractor;
- 
 %0A    %0A  
@@ -1476,17 +1476,16 @@
 *%0A     *
- 
  Move su
@@ -2292,17 +2292,16 @@
 t;%0A    %7D
- 
 %0A%0A    /*
@@ -2830,24 +2830,79 @@
 ocInBody) %7B%0A
+                String parentId = generateDid(parent);%0A
             
@@ -2934,35 +2934,16 @@
 ey, 
-generateSuperdocDid(
 parent
-)
+Id
 );%0A 
@@ -3009,20 +3009,83 @@
 tyType, 
-null
+generateSubdocDid(inbodyDoc,%0A                        subentityType)
 , inbody
@@ -3096,16 +3096,17 @@
  null);%0A
+%0A
         
@@ -3422,32 +3422,40 @@
  of this entity%0A
+     * %0A
      * @param en
@@ -3511,24 +3511,16 @@
 generate
-Superdoc
 Did(Enti
@@ -3908,10 +3908,424 @@
 %7D%0A    %7D%0A
+    %0A    /**%0A     * calculates the Determinsitic ID of subdoc entity%0A     * %0A     * @param subEntityBody%0A     * @param parentId%0A     * @param subEntityType%0A     * @return%0A     */%0A    protected String generateSubdocDid(Map%3CString, Object%3E subEntityBody, String subEntityType) %7B%0A        MongoEntity subEntity = new MongoEntity(subEntityType, null, subEntityBody, null);%0A        return generateDid(subEntity);%0A    %7D%0A%0A
 %7D%0A

update superdocconverter to generate subdoc Did during transform