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

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

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

public class Draft2MetadataCallback implements Draft2PortProcessorCallback {

  private Map<String, Map<String, Object>> pathToMetadata = 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(clonedValue, pathToMetadata.get(path));
        }
      }

      List<Map<String, Object>> secondaryFiles = Draft2FileValueHelper.getSecondaryFiles(clonedValue);
      if (secondaryFiles != null) {
        for (Map<String, Object> secondaryFileValue : secondaryFiles) {
          String subpath = Draft2FileValueHelper.getPath(secondaryFileValue);
          if (pathToMetadata.containsKey(subpath)) {
            Map<String, Object> metadata = Draft2FileValueHelper.getMetadata(secondaryFileValue);
            if (metadata == null || metadata.isEmpty()) {
              Draft2FileValueHelper.setMetadata(secondaryFileValue, pathToMetadata.get(subpath));
            }
          }
        }
      }
      return new Draft2PortProcessorResult(clonedValue, true);
    }
    return new Draft2PortProcessorResult(value, false);
  }
  
}

@@ -2408,29 +2408,16 @@
 etadata(
-clonedValue, 
 pathToMe
@@ -2428,24 +2428,37 @@
 ta.get(path)
+, clonedValue
 );%0A        %7D
@@ -3017,28 +3017,8 @@
 ata(
-secondaryFileValue, 
 path
@@ -3040,16 +3040,36 @@
 subpath)
+, secondaryFileValue
 );%0A     

fix metadata processor