-- | Adds a secondary instance (extended version).
addSecEx :: Bool -> Node -> Instance.Instance -> T.Ndx -> T.OpResult Node
addSecEx force t inst pdx =
  let iname = Instance.idx inst
      old_peers = peers t
      old_mem = fMem t
      new_dsk = fDsk t - Instance.dsk inst
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      secondary_needed_mem = if Instance.usesSecMem inst
                               then Instance.mem inst
                               else 0
      new_peem = P.find pdx old_peers + secondary_needed_mem
      new_peers = P.add pdx new_peem old_peers
      new_rmem = max (rMem t) new_peem
      new_prem = fromIntegral new_rmem / tMem t
      new_failn1 = old_mem <= new_rmem
      new_dp = computeNewPDsk t new_free_sp new_dsk
      old_load = utilLoad t
      new_load = old_load { T.dskWeight = T.dskWeight old_load +
                                          T.dskWeight (Instance.util inst) }
      strict = not force
  in case () of
       _ | not (Instance.hasSecondary inst) -> Bad T.FailDisk
         | new_dsk <= 0 -> Bad T.FailDisk
         | new_dsk < loDsk t && strict -> Bad T.FailDisk
         | exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | secondary_needed_mem >= old_mem && strict -> Bad T.FailMem
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | otherwise ->
           let new_slist = iname:sList t
               r = t { sList = new_slist, fDsk = new_dsk
                     , peers = new_peers, failN1 = new_failn1
                     , rMem = new_rmem, pDsk = new_dp
                     , pRem = new_prem, utilLoad = new_load
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- * Stats functions

-- | Computes the amount of available disk on a given node.
addSecEx :: Bool -> Node -> Instance.Instance -> T.Ndx -> T.OpResult Node
addSecEx force t inst pdx =
  let iname = Instance.idx inst
      old_peers = peers t
      old_mem = fMem t
      new_dsk = fDsk t - Instance.dsk inst
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      secondary_needed_mem = if Instance.usesSecMem inst
                               then Instance.mem inst
                               else 0
      new_peem = P.find pdx old_peers + secondary_needed_mem
      new_peers = P.add pdx new_peem old_peers
      new_rmem = max (rMem t) new_peem
      new_prem = fromIntegral new_rmem / tMem t
      new_failn1 = old_mem <= new_rmem
      new_dp = computeNewPDsk t new_free_sp new_dsk
      old_load = utilLoad t
      new_load = old_load { T.dskWeight = T.dskWeight old_load +
                                          T.dskWeight (Instance.util inst) }
      strict = not force
  in case () of
       _ | not (Instance.hasSecondary inst) -> Bad T.FailDisk
         | new_dsk <= 0 -> Bad T.FailDisk
         | new_dsk < loDsk t && strict -> Bad T.FailDisk
         | exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | secondary_needed_mem >= old_mem && strict -> Bad T.FailMem
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | otherwise ->
           let new_slist = iname:sList t
               r = t { sList = new_slist, fDsk = new_dsk
                     , peers = new_peers, failN1 = new_failn1
                     , rMem = new_rmem, pDsk = new_dp
                     , pRem = new_prem, utilLoad = new_load
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- * Stats functions

-- | Computes the amount of available disk on a given node.
addSecEx force t inst pdx =
  let iname = Instance.idx inst
      old_peers = peers t
      old_mem = fMem t
      new_dsk = fDsk t - Instance.dsk inst
      new_free_sp = calcNewFreeSpindles True t inst
      new_inst_sp = calcSpindleUse True t inst
      secondary_needed_mem = if Instance.usesSecMem inst
                               then Instance.mem inst
                               else 0
      new_peem = P.find pdx old_peers + secondary_needed_mem
      new_peers = P.add pdx new_peem old_peers
      new_rmem = max (rMem t) new_peem
      new_prem = fromIntegral new_rmem / tMem t
      new_failn1 = old_mem <= new_rmem
      new_dp = computeNewPDsk t new_free_sp new_dsk
      old_load = utilLoad t
      new_load = old_load { T.dskWeight = T.dskWeight old_load +
                                          T.dskWeight (Instance.util inst) }
      strict = not force
  in case () of
       _ | not (Instance.hasSecondary inst) -> Bad T.FailDisk
         | new_dsk <= 0 -> Bad T.FailDisk
         | new_dsk < loDsk t && strict -> Bad T.FailDisk
         | exclStorage t && new_free_sp < 0 -> Bad T.FailSpindles
         | new_inst_sp > hiSpindles t && strict -> Bad T.FailDisk
         | secondary_needed_mem >= old_mem && strict -> Bad T.FailMem
         | new_failn1 && not (failN1 t) && strict -> Bad T.FailMem
         | otherwise ->
           let new_slist = iname:sList t
               r = t { sList = new_slist, fDsk = new_dsk
                     , peers = new_peers, failN1 = new_failn1
                     , rMem = new_rmem, pDsk = new_dp
                     , pRem = new_prem, utilLoad = new_load
                     , instSpindles = new_inst_sp
                     , fSpindles = new_free_sp
                     }
           in Ok r

-- * Stats functions

-- | Computes the amount of available disk on a given node.