-- | Update the CPU load of one instance based on the reports.
-- Fail if instance CPU load is not (yet) available. However, do
-- accpet missing load data for instances on offline nodes, as well
-- as old load data for recently migrated instances.
updateCPUInstance :: Node.List
                  -> Container.Container AllReports
                  -> Set.Set String
                  -> [String]
                  -> Instance.Instance
                  -> Result Instance.Instance
updateCPUInstance nl reports xeninsts evacuated inst =
  let name = Instance.name inst
      nidx = Instance.pNode inst
  in if name `Set.member` xeninsts
    then let onNodeLoad = findInstanceLoad name (Container.find nidx reports)
             allLoads = mapMaybe (findInstanceLoad name)
                          $ Container.elems reports
         in case () of
           _ | Just load <- onNodeLoad ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | (load:_) <- allLoads ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | Node.offline $ Container.find nidx nl ->
                 return $ inst { Instance.util = zeroUtil }
           _ | Instance.name inst `elem` evacuated ->
                 return $ inst { Instance.util = zeroUtil }
           _ -> fail $ "Xen CPU data unavailable for " ++ name
    else let rep = rTotal $ Container.find nidx reports
         in case rep of MonD.CPUavgloadReport (CPUavgload _ _ ndload) ->
                          let w = ndload * fromIntegral (Instance.vcpus inst)
                                  / (fromIntegral . Node.uCpu
                                       $ Container.find nidx nl)
                          in return $ inst { Instance.util =
                                                zeroUtil { cpuWeight = w }}
                        _ -> fail $ "CPU data unavailable for node of " ++ name

-- | Update CPU usage data based on the collected reports. That is, get the
-- CPU usage of all instances from the reports and also update the nodes
-- accordingly.
updateCPUInstance :: Node.List
                  -> Container.Container AllReports
                  -> Set.Set String
                  -> [String]
                  -> Instance.Instance
                  -> Result Instance.Instance
updateCPUInstance nl reports xeninsts evacuated inst =
  let name = Instance.name inst
      nidx = Instance.pNode inst
  in if name `Set.member` xeninsts
    then let onNodeLoad = findInstanceLoad name (Container.find nidx reports)
             allLoads = mapMaybe (findInstanceLoad name)
                          $ Container.elems reports
         in case () of
           _ | Just load <- onNodeLoad ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | (load:_) <- allLoads ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | Node.offline $ Container.find nidx nl ->
                 return $ inst { Instance.util = zeroUtil }
           _ | Instance.name inst `elem` evacuated ->
                 return $ inst { Instance.util = zeroUtil }
           _ -> fail $ "Xen CPU data unavailable for " ++ name
    else let rep = rTotal $ Container.find nidx reports
         in case rep of MonD.CPUavgloadReport (CPUavgload _ _ ndload) ->
                          let w = ndload * fromIntegral (Instance.vcpus inst)
                                  / (fromIntegral . Node.uCpu
                                       $ Container.find nidx nl)
                          in return $ inst { Instance.util =
                                                zeroUtil { cpuWeight = w }}
                        _ -> fail $ "CPU data unavailable for node of " ++ name

-- | Update CPU usage data based on the collected reports. That is, get the
-- CPU usage of all instances from the reports and also update the nodes
-- accordingly.
updateCPUInstance nl reports xeninsts evacuated inst =
  let name = Instance.name inst
      nidx = Instance.pNode inst
  in if name `Set.member` xeninsts
    then let onNodeLoad = findInstanceLoad name (Container.find nidx reports)
             allLoads = mapMaybe (findInstanceLoad name)
                          $ Container.elems reports
         in case () of
           _ | Just load <- onNodeLoad ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | (load:_) <- allLoads ->
                 return $ inst { Instance.util = zeroUtil { cpuWeight = load } }
           _ | Node.offline $ Container.find nidx nl ->
                 return $ inst { Instance.util = zeroUtil }
           _ | Instance.name inst `elem` evacuated ->
                 return $ inst { Instance.util = zeroUtil }
           _ -> fail $ "Xen CPU data unavailable for " ++ name
    else let rep = rTotal $ Container.find nidx reports
         in case rep of MonD.CPUavgloadReport (CPUavgload _ _ ndload) ->
                          let w = ndload * fromIntegral (Instance.vcpus inst)
                                  / (fromIntegral . Node.uCpu
                                       $ Container.find nidx nl)
                          in return $ inst { Instance.util =
                                                zeroUtil { cpuWeight = w }}
                        _ -> fail $ "CPU data unavailable for node of " ++ name

-- | Update CPU usage data based on the collected reports. That is, get the
-- CPU usage of all instances from the reports and also update the nodes
-- accordingly.