module XMonad.Hooks.InsertPosition (
    
    
    insertPosition
    ,Focus(..), Position(..)
    ) where
import XMonad(ManageHook, MonadReader(ask))
import qualified XMonad.StackSet as W
import Control.Applicative((<$>))
import Data.Maybe(fromMaybe)
import Data.List(find)
import Data.Monoid(Endo(Endo))
data Position = Master | End | Above | Below
data Focus = Newer | Older
insertPosition :: Position -> Focus -> ManageHook
insertPosition pos foc = Endo . g <$> ask
  where
    g w = viewingWs w (updateFocus w . ins w . W.delete' w)
    ins w = (\f ws -> fromMaybe id (W.focusWindow <$> W.peek ws) $ f ws) $
        case pos of
            Master -> W.insertUp w . W.focusMaster
            End    -> insertDown w . W.modify' focusLast'
            Above  -> W.insertUp w
            Below  -> insertDown w
    updateFocus =
        case foc of
            Older -> const id
            Newer -> W.focusWindow
viewingWs :: (Eq a, Eq s, Eq i, Show i) =>a-> (W.StackSet i l a s sd -> W.StackSet i l a s sd)-> W.StackSet i l a s sd-> W.StackSet i l a s sd
viewingWs w f = do
    i <- W.tag . W.workspace . W.current
    ws <- find (elem w . W.integrate' . W.stack) . W.workspaces
    maybe id (fmap (W.view i . f) . W.view . W.tag) ws
insertDown :: (Eq a) => a -> W.StackSet i l a s sd -> W.StackSet i l a s sd
insertDown w = W.swapDown . W.insertUp w
focusLast' ::  W.Stack a -> W.Stack a
focusLast' st = let ws = W.integrate st
    in W.Stack (last ws) (tail $ reverse ws) []