package org.rabix.engine;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.rabix.bindings.helper.URIHelper;
import org.rabix.bindings.model.ApplicationPort;
import org.rabix.bindings.model.Context;
import org.rabix.bindings.model.Job;
import org.rabix.bindings.model.Job.JobStatus;
import org.rabix.bindings.model.dag.DAGLinkPort.LinkPortType;
import org.rabix.bindings.model.dag.DAGNode;
import org.rabix.common.helper.CloneHelper;
import org.rabix.common.helper.InternalSchemaHelper;
import org.rabix.engine.db.DAGNodeDB;
import org.rabix.engine.model.ContextRecord;
import org.rabix.engine.model.JobRecord;
import org.rabix.engine.model.VariableRecord;
import org.rabix.engine.service.ContextRecordService;
import org.rabix.engine.service.JobRecordService;
import org.rabix.engine.service.VariableRecordService;

public class JobHelper {

  public static String generateId() {
    return UUID.randomUUID().toString();
  }
  
  public static Set<Job> createReadyJobs(JobRecordService jobRecordService, VariableRecordService variableRecordService, ContextRecordService contextRecordService, DAGNodeDB dagNodeDB, String contextId) {
    Set<Job> jobs = new HashSet<>();
    List<JobRecord> jobRecords = jobRecordService.findReady(contextId);

    if (!jobRecords.isEmpty()) {
      for (JobRecord job : jobRecords) {
        jobs.add(createJob(job, JobStatus.READY, jobRecordService, variableRecordService, contextRecordService, dagNodeDB));
      }
    }
    return jobs;
  }
  
  public static Job createJob(JobRecord job, JobStatus status, JobRecordService jobRecordService, VariableRecordService variableRecordService, ContextRecordService contextRecordService, DAGNodeDB dagNodeDB) {
    DAGNode node = dagNodeDB.get(InternalSchemaHelper.normalizeId(job.getId()), job.getRootId());

    boolean autoBoxingEnabled = true;   // get from configuration
    
    Map<String, Object> inputs = new HashMap<>();
    List<VariableRecord> inputVariables = variableRecordService.find(job.getId(), LinkPortType.INPUT, job.getRootId());
    for (VariableRecord inputVariable : inputVariables) {
      Object value = CloneHelper.deepCopy(inputVariable.getValue());
      ApplicationPort port = node.getApp().getInput(inputVariable.getPortId());
      if (port != null && autoBoxingEnabled) {
        if (port.isList() && !(value instanceof List)) {
          List<Object> transformed = new ArrayList<>();
          transformed.add(value);
          value = transformed;
        }
      }
      inputs.put(inputVariable.getPortId(), value);
    }
    ContextRecord contextRecord = contextRecordService.find(job.getRootId());
    Context context = new Context(job.getRootId(), contextRecord.getConfig());
    String encodedApp = URIHelper.createDataURI(node.getApp().serialize());
    return new Job(job.getExternalId(), job.getParentId(), job.getRootId(), job.getId(), encodedApp, status, inputs, null, context, null);
  }
  
  public static Job fillOutputs(Job job, JobRecordService jobRecordService, VariableRecordService variableRecordService) {
    JobRecord jobRecord = jobRecordService.findRoot(job.getContext().getId());
    List<VariableRecord> outputVariables = variableRecordService.find(jobRecord.getId(), LinkPortType.OUTPUT, job.getContext().getId());
    
    Map<String, Object> outputs = new HashMap<>();
    for (VariableRecord outputVariable : outputVariables) {
      outputs.put(outputVariable.getPortId(), outputVariable.getValue());
    }
    return Job.cloneWithOutputs(job, outputs);
  }
  
}

@@ -946,34 +946,169 @@
 ce;%0A
-%0Apublic class JobHelper %7B%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Apublic class JobHelper %7B%0A%0A  private static Logger logger = LoggerFactory.getLogger(JobHelper.class);%0A  
 %0A  p
@@ -2117,24 +2117,140 @@
 ration%0A    %0A
+    StringBuilder inputsLogBuilder = new StringBuilder(%22%5Cn ---- JobRecord %22).append(job.getId()).append(%22%5Cn%22);%0A    %0A
     Map%3CStri
@@ -2873,53 +2873,232 @@
 puts
-.put(inputVariable.getPortId(), value);%0A    %7D
+LogBuilder.append(%22 ---- Input %22).append(inputVariable.getPortId()).append(%22, value %22).append(value).append(%22%5Cn%22);%0A      inputs.put(inputVariable.getPortId(), value);%0A    %7D%0A    logger.debug(inputsLogBuilder.toString());%0A    
 %0A   

add extra logging