package org.rabix.engine.memory.impl;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.rabix.bindings.model.Job;
import org.rabix.bindings.model.Job.JobStatus;
import org.rabix.engine.repository.JobRepository;

import com.google.inject.Inject;

public class InMemoryJobRepository implements JobRepository {

  Map<UUID, Map<UUID, JobEntity>> jobRepository;
  
  @Inject
  public InMemoryJobRepository() {
    this.jobRepository = new ConcurrentHashMap<UUID, Map<UUID, JobEntity>>();
  }

  @Override
  public synchronized void insert(Job job, UUID groupId, String producedByNode) {
    Map<UUID, JobEntity> rootJobs = jobRepository.get(job.getRootId());
    if(rootJobs == null) {
      rootJobs = new HashMap<UUID, JobEntity>();
      rootJobs.put(job.getId(), new JobEntity(job, groupId, producedByNode));
      jobRepository.put(job.getRootId(), rootJobs);
    }
    else {
      rootJobs.put(job.getId(), new JobEntity(job, groupId, producedByNode));
    }
  }

  @Override
  public synchronized void update(Job job) {
    Map<UUID, JobEntity> rootJobs = jobRepository.get(job.getRootId());
    rootJobs.get(job.getId()).setJob(job);
  }

  @Override
  public synchronized void updateBackendId(UUID jobId, UUID backendId) {
    if(getJobEntity(jobId) != null) {
      getJobEntity(jobId).setBackendId(backendId);
    }
  }

  @Override
  public synchronized void dealocateJobs(UUID backendId) {
    for(Map<UUID, JobEntity> rootJobs: jobRepository.values()) {
      for(JobEntity job: rootJobs.values()) {
        if(job.getBackendId().equals(backendId) && job.getJob().getStatus().equals(JobStatus.READY)) {
          job.setBackendId(null);
        }
      }
    }
  }

  @Override
  public synchronized Job get(UUID id) {
    return getJobEntity(id) != null ? getJobEntity(id).getJob(): null;
  }

  @Override
  public synchronized Set<Job> get() {
    Set<Job> allJobs = new HashSet<Job>();
    for(Map<UUID, JobEntity> rootJobs: jobRepository.values()) {
      for(JobEntity job: rootJobs.values()) {
        allJobs.add(job.getJob());
      }
    }
    return allJobs;
  }

  @Override
  public synchronized Set<Job> getByRootId(UUID rootId) {
    Set<Job> rootJobs = new HashSet<Job>();
    Map<UUID, JobEntity> jobs = jobRepository.get(rootId);
    for(JobEntity job: jobs.values()) {
      rootJobs.add(job.getJob());
    }
    return rootJobs;
  }

  @Override
  public synchronized Set<UUID> getBackendsByRootId(UUID rootId) {
    Set<UUID> backends = new HashSet<UUID>();
    Map<UUID, JobEntity> jobs = jobRepository.get(rootId);
    for(JobEntity job: jobs.values()) {
      backends.add(job.getBackendId());
    }
    return backends;
  }

  @Override
  public synchronized Set<Job> getReadyJobsByGroupId(UUID groupId) {
    Set<Job> groupIdJobs = new HashSet<Job>();
    for(Map<UUID, JobEntity> rootJobs: jobRepository.values()) {
      for(JobEntity job: rootJobs.values()) {
        if(job.getGroupId() != null && job.getGroupId().equals(groupId)) {
          groupIdJobs.add(job.getJob());
        }
      }
    }
    return groupIdJobs;
  }

  @Override
  public synchronized Set<JobEntity> getReadyFree() {
    Set<JobEntity> readyFreeJobs = new HashSet<JobEntity>();
    for(Map<UUID, JobEntity> rootJobs: jobRepository.values()) {
      for(JobEntity job: rootJobs.values()) {
        if(job.getBackendId() == null && job.getJob().getStatus().equals(JobStatus.READY)) {
          readyFreeJobs.add(job);
        }
      }
    }
    return readyFreeJobs;
  }

  @Override
  public void updateBackendIds(Iterator<JobEntity> entities) {
//    while(jobBackendPair.hasNext()) {
//      JobBackendPair jbp = jobBackendPair.next();
//      updateBackendId(jbp.getJobId(), jbp.getBackendId());
//    }
  }

  @Override
  public UUID getBackendId(UUID jobId) {
    return getJobEntity(jobId) != null ? getJobEntity(jobId).getBackendId() : null;
    
  }

  @Override
  public JobStatus getStatus(UUID id) {
    return getJobEntity(id) != null ? getJobEntity(id).getJob().getStatus() : null;
  }
  
  private JobEntity getJobEntity(UUID jobId) {
    for(Map<UUID, JobEntity> rootJobs: jobRepository.values()) {
      if(rootJobs.get(jobId) != null) {
        return rootJobs.get(jobId);
      }
    }
    return null;
  }
  
}

@@ -3708,26 +3708,24 @@
 entities) %7B%0A
-//
     while(jo
@@ -3722,30 +3722,24 @@
   while(
-jobBackendPair
+entities
 .hasNext
@@ -3744,18 +3744,16 @@
 xt()) %7B%0A
-//
       Jo
@@ -3757,40 +3757,29 @@
  Job
-BackendPair jbp = jobBackendPair
+Entity jbp = entities
 .nex
@@ -3783,18 +3783,16 @@
 next();%0A
-//
       up
@@ -3815,16 +3815,22 @@
 p.getJob
+().get
 Id(), jb
@@ -3852,10 +3852,8 @@
 ));%0A
-//
     

Implement update backendIds with JobEntity