package org.rabix.bindings.draft2.processor.callback;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rabix.bindings.draft2.helper.Draft2FileValueHelper;
import org.rabix.bindings.draft2.helper.Draft2SchemaHelper;
import org.rabix.bindings.draft2.processor.Draft2PortProcessorCallback;
import org.rabix.bindings.draft2.processor.Draft2PortProcessorResult;
import org.rabix.bindings.model.ApplicationPort;
import org.rabix.common.helper.CloneHelper;

public class Draft2MetadataCallback implements Draft2PortProcessorCallback {

  private Map<String, Map<String, Object>> pathToMetadata = new HashMap<>();
  private Map<String, Map<String, Object>> outputMetadata = new HashMap<>();
  
  public Draft2MetadataCallback(Map<String, Object> inputs) {
    mapPathsToMetadata(inputs);
  }
  
  /**
   * Extract paths from unknown data
   */
  public void mapPathsToMetadata(Object value) {
    if (value == null) {
      return;
    } else if (Draft2SchemaHelper.isFileFromValue(value)) {
      String path = Draft2FileValueHelper.getPath(value);
      if (!pathToMetadata.containsKey(path)) {
        pathToMetadata.put(path, Draft2FileValueHelper.getMetadata(value));
      }

      List<Map<String, Object>> secondaryFiles = Draft2FileValueHelper.getSecondaryFiles(value);
      if (secondaryFiles != null) {
        for (Object subvalue : secondaryFiles) {
          String subpath = Draft2FileValueHelper.getPath(subvalue);
          if (!pathToMetadata.containsKey(subpath)) {
            pathToMetadata.put(subpath, Draft2FileValueHelper.getMetadata(subvalue));
          }
        }
      }
    } else if (value instanceof List<?>) {
      for (Object subvalue : ((List<?>) value)) {
        mapPathsToMetadata(subvalue);
      }
    } else if (value instanceof Map<?, ?>) {
      for (Object subvalue : ((Map<?, ?>) value).values()) {
        mapPathsToMetadata(subvalue);
      }
    }
  }
  
  @Override
  public Draft2PortProcessorResult process(Object value, ApplicationPort port) throws Exception {
    if (Draft2SchemaHelper.isFileFromValue(value)) {
      Object clonedValue = CloneHelper.deepCopy(value);
      String path = Draft2FileValueHelper.getPath(clonedValue);
      if (pathToMetadata.containsKey(path)) {
        Map<String, Object> metadata = Draft2FileValueHelper.getMetadata(clonedValue);
        if (metadata == null || metadata.isEmpty()) {
          Draft2FileValueHelper.setMetadata(pathToMetadata.get(path), clonedValue);
        }
      }
      outputMetadata.put(path, Draft2FileValueHelper.getMetadata(clonedValue));

      List<Map<String, Object>> secondaryFiles = Draft2FileValueHelper.getSecondaryFiles(clonedValue);
      if (secondaryFiles != null) {
        for (Map<String, Object> secondaryFileValue : secondaryFiles) {
          String subpath = Draft2FileValueHelper.getPath(secondaryFileValue);
          Map<String, Object> metadata = Draft2FileValueHelper.getMetadata(secondaryFileValue);

          if (pathToMetadata.containsKey(subpath)) {
            if (metadata == null || metadata.isEmpty()) {
              Draft2FileValueHelper.setMetadata(pathToMetadata.get(subpath), secondaryFileValue);
            }
          }
          if ((metadata == null || metadata.isEmpty()) && outputMetadata.containsKey(subpath)) {
            Draft2FileValueHelper.setMetadata(outputMetadata.get(subpath), secondaryFileValue);
          }
        }
      }
      return new Draft2PortProcessorResult(clonedValue, true);
    }
    return new Draft2PortProcessorResult(value, false);
  }
  
}

@@ -2334,32 +2334,100 @@
 a(clonedValue);%0A
+        Map%3CString, Object%3E newMetadata = pathToMetadata.get(path);%0A
         if (meta
@@ -2435,43 +2435,69 @@
 ata 
-=
+!
 = null
- %7C%7C metadata.isEmpty()) %7B%0A  
+) %7B%0A          newMetadata.putAll(metadata);%0A        %7D%0A
     
@@ -2530,38 +2530,35 @@
 setMetadata(
-pathTo
+new
 Metadata
 .get(path), 
@@ -2545,26 +2545,16 @@
 Metadata
-.get(path)
 , cloned
@@ -2561,26 +2561,16 @@
 Value);%0A
-        %7D%0A
       %7D%0A
@@ -2941,32 +2941,98 @@
 lue);%0A          
+%0A          if (pathToMetadata.containsKey(subpath)) %7B%0A            
 Map%3CString, Obje
@@ -3101,17 +3101,18 @@
 Value);%0A
-%0A
+  
         
@@ -3117,50 +3117,67 @@
     
-if (pathToMetadata.containsKey(sub
+Map%3CString, Object%3E newMetadata = pathToMetadata.get(
 path)
-) %7B
+;
 %0A   
@@ -3202,43 +3202,77 @@
 ata 
-=
+!
 = null
- %7C%7C metadata.isEmpty()) %7B%0A  
+) %7B%0A              newMetadata.putAll(metadata);%0A            %7D%0A
     
@@ -3313,30 +3313,27 @@
 etadata(
-pathTo
+new
 Metadata
 .get(sub
@@ -3320,37 +3320,24 @@
 (newMetadata
-.get(subpath)
 , secondaryF
@@ -3349,34 +3349,32 @@
 lue);%0A          
-  
 %7D%0A          %7D%0A  
@@ -3361,33 +3361,117 @@
     %7D%0A          
-%7D
+Map%3CString, Object%3E metadata = Draft2FileValueHelper.getMetadata(secondaryFileValue);
 %0A          if ((

fix metadata callback