fillResidual :: (EuclideanSpace3D, ResidualSpace) -- ^ Package and picked residual space
           -> Quantity -- ^ quantity of packages (to be maximized in the filling)
           -> AxeOrder -- ^ axe fill order
           -> Maybe (EuclideanSpace3D, [Vec3], Quantity) -- ^ used package, all translation vectors and used quantity or @Nothing@
                                                       -- if not a single item fits
fillResidual (space, residual) q order
  | order == [Y, Z]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, Y]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Y]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Y, X]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Z]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, X]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | otherwise
  = Nothing
  where
    sresidual = S.size $ rspace residual
    sspace = mapVec (1/) $ S.size space
    fits = sresidual `pointwise` sspace
    (xs, ys, zs) = ( floor (vx fits) -1
                   , floor (vy fits) -1
                   , min (floor (vz fits) -1 ) 0
                   )
    minq = min q ((xs + 1) * (ys + 1) * (zs + 1))


-- | Try to fill a residual space 'rspace'.
-- in contrast to @fillResidual@ the used freespace is also returned
fillResidual :: (EuclideanSpace3D, ResidualSpace) -- ^ Package and picked residual space
           -> Quantity -- ^ quantity of packages (to be maximized in the filling)
           -> AxeOrder -- ^ axe fill order
           -> Maybe (EuclideanSpace3D, [Vec3], Quantity)
fillResidual (space, residual) q order
  | order == [Y, Z]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, Y]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Y]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Y, X]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Z]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, X]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | otherwise
  = Nothing
  where
    sresidual = S.size $ rspace residual
    sspace = mapVec (1/) $ S.size space
    fits = sresidual `pointwise` sspace
    (xs, ys, zs) = ( floor (vx fits) -1
                   , floor (vy fits) -1
                   , min (floor (vz fits) -1 ) 0
                   )
    minq = min q ((xs + 1) * (ys + 1) * (zs + 1))


-- | Try to fill a residual space 'rspace'.
-- in contrast to @fillResidual@ the used freespace is also returned
fillResidual (space, residual) q order
  | order == [Y, Z]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, Y]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Y]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Y, X]
  , facs <- take minq
           [ Vec3 x y z
           | y <- [0 .. fromIntegral ys]
           , x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [X, Z]
  , facs <- take minq
           [ Vec3 x y z
           | x <- [0 .. fromIntegral xs]
           , z <- [0 .. fromIntegral zs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | order == [Z, X]
  , facs <- take minq
           [ Vec3 x y z
           | z <- [0 .. fromIntegral zs]
           , x <- [0 .. fromIntegral xs]
           , y <- [0 .. fromIntegral ys]
           ]
  , not $ L.null facs
  = Just (space, facs, minq)
  | otherwise
  = Nothing
  where
    sresidual = S.size $ rspace residual
    sspace = mapVec (1/) $ S.size space
    fits = sresidual `pointwise` sspace
    (xs, ys, zs) = ( floor (vx fits) -1
                   , floor (vy fits) -1
                   , min (floor (vz fits) -1 ) 0
                   )
    minq = min q ((xs + 1) * (ys + 1) * (zs + 1))


-- | Try to fill a residual space 'rspace'.
-- in contrast to @fillResidual@ the used freespace is also returned