package com.hubspot.singularity.scheduler;

import java.util.List;
import java.util.Set;

import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.hubspot.singularity.SingularityPendingTask;
import com.hubspot.singularity.SingularityRack;
import com.hubspot.singularity.SingularitySlave;
import com.hubspot.singularity.SingularityTaskId;
import com.hubspot.singularity.data.RackManager;
import com.hubspot.singularity.data.SlaveManager;
import com.hubspot.singularity.data.TaskManager;

public class SingularitySchedulerStateCache {

  private final TaskManager taskManager;
  
  private final SlaveManager slaveManager;
  private final RackManager rackManager;
  
  private Optional<List<SingularityTaskId>> activeTaskIds;
  private Optional<List<SingularityPendingTask>> scheduledTasks;
  private Optional<List<SingularityRack>> decomissioningRacks;
  private Optional<Set<String>> decomissioningRackIds;
  private Optional<List<SingularitySlave>> decomissioningSlaves;
  private Optional<Set<String>> decomissioningSlaveIds;
  private Optional<List<SingularityTaskId>> cleaningTasks;
  
  @Inject
  public SingularitySchedulerStateCache(TaskManager taskManager, SlaveManager slaveManager, RackManager rackManager) {
    this.taskManager = taskManager;
    this.slaveManager = slaveManager;
    this.rackManager = rackManager;
    
    activeTaskIds = Optional.absent();
    scheduledTasks = Optional.absent();
    decomissioningRacks = Optional.absent();
    decomissioningRackIds = Optional.absent();
    decomissioningSlaves = Optional.absent();
    decomissioningSlaveIds = Optional.absent();
    cleaningTasks = Optional.absent();
  }
  
  public List<SingularityTaskId> getActiveTaskIds() {
    if (!activeTaskIds.isPresent()) {
      activeTaskIds = Optional.of(taskManager.getActiveTaskIds());
    }
    
    return activeTaskIds.get();
  }

  public List<SingularityPendingTask> getScheduledTasks() {
    if (!scheduledTasks.isPresent()) {
      scheduledTasks = Optional.of(taskManager.getPendingTasks());
    }
    
    return scheduledTasks.get();
  }
  
  private void checkDecomissioningRacks() {
    if (decomissioningRacks.isPresent()) {
      return;
    }
     
    decomissioningRacks = Optional.of(rackManager.getDecomissioningObjects());
    Set<String> decomissioningRacksIdsSet = Sets.newHashSetWithExpectedSize(decomissioningRacks.get().size());
    for (SingularityRack rack : decomissioningRacks.get()) {
      decomissioningRacksIdsSet.add(rack.getId());
    }
    decomissioningRackIds = Optional.of(decomissioningRacksIdsSet);
  }
  
  public List<SingularityRack> getDecomissioningRacks() {
    checkDecomissioningRacks();
    
    return decomissioningRacks.get();
  }
  
  private void checkDecomissioningSlaves() {
    if (decomissioningSlaves.isPresent()) {
      return;
    }
    
    decomissioningSlaves = Optional.of(slaveManager.getDecomissioningObjects());
    Set<String> decomissioningSlaveIdsSet = Sets.newHashSetWithExpectedSize(decomissioningSlaves.get().size());
    for (SingularitySlave slave : decomissioningSlaves.get()) {
      decomissioningSlaveIdsSet.add(slave.getId());
    }
    decomissioningSlaveIds = Optional.of(decomissioningSlaveIdsSet);
  }
  
  public List<SingularitySlave> getDecomissioningSlaves() {
    checkDecomissioningSlaves();
    
    return decomissioningSlaves.get();
  }
  
  public List<SingularityTaskId> getCleaningTasks() {
    if (!cleaningTasks.isPresent()) {
      List<SingularityTaskId> mutableList = Lists.newArrayList(taskManager.getCleanupTaskIds());
      cleaningTasks = Optional.of(mutableList);
    }
    
    return cleaningTasks.get();   
  }
  
  public boolean isSlaveDecomissioning(String slaveId) {
    checkDecomissioningSlaves();
    
    return decomissioningSlaveIds.get().contains(slaveId);
  }
  
  public boolean isRackDecomissioning(String rackId) {
    checkDecomissioningRacks();
    
    return decomissioningRackIds.get().contains(rackId);
  }

}

@@ -1854,35 +1854,38 @@
 veTaskIds = 
-Optional.of
+getMutableList
 (taskManager
@@ -2076,27 +2076,30 @@
 Tasks = 
-Optional.of
+getMutableList
 (taskMan
@@ -3466,239 +3466,342 @@
 %0A  p
-ublic List%3CSingularityTaskId%3E getCleaningTasks() %7B%0A    if (!cleaningTasks.isPresent()) %7B%0A      List%3CSingularityTaskId%3E mutableList = Lists.newArrayList(taskManager.getCleanupTaskIds());%0A      cleaningTasks = Optional.of(mutableList
+rivate %3CT%3E Optional%3CList%3CT%3E%3E getMutableList(List%3CT%3E immutableList) %7B%0A    List%3CT%3E mutableList = Lists.newArrayList(immutableList);%0A    return Optional.of(mutableList);%0A  %7D%0A  %0A  public List%3CSingularityTaskId%3E getCleaningTasks() %7B%0A    if (!cleaningTasks.isPresent()) %7B%0A      cleaningTasks = getMutableList(taskManager.getCleanupTaskIds()
 );%0A 

use mutable lists in cache