    {-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module       : XMonad.Layout.ToggleLayouts
    -- Copyright    : (c) David Roundy <droundy@darcs.net>
    -- License      : BSD
    --
    -- Maintainer   : none
    -- Stability    : unstable
    -- Portability  : portable
    --
    -- A module to toggle between two layouts.
    -----------------------------------------------------------------------------

    module XMonad.Layout.ToggleLayouts (
        -- * Usage
        -- $usage
        toggleLayouts, ToggleLayout(..)
        ) where

    import XMonad
    import XMonad.StackSet (Workspace (..))

    -- $usage
    -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
    --
    -- > import XMonad.Layout.ToggleLayouts
    --
    -- Then edit your @layoutHook@ by adding the ToggleLayouts layout:
    --
    -- > myLayout = toggleLayouts Full (Tall 1 (3/100) (1/2)) ||| etc..
    -- > main = xmonad defaultConfig { layoutHook = myLayout }
    --
    -- For more detailed instructions on editing the layoutHook see:
    --
    -- "XMonad.Doc.Extending#Editing_the_layout_hook"
    --
    -- To toggle between layouts add a key binding like
    --
    -- >    , ((modm .|. controlMask, xK_space), sendMessage ToggleLayout)
    --
    -- or a key binding like
    --
    -- >    , ((modm .|. controlMask, xK_space), sendMessage (Toggle "Full"))
    --
    -- For detailed instruction on editing the key binding see:
    --
    -- "XMonad.Doc.Extending#Editing_key_bindings".

    data ToggleLayouts lt lf a = ToggleLayouts Bool (lt a) (lf a) deriving (Read,Show)
    data ToggleLayout = ToggleLayout | Toggle String deriving (Read,Show,Typeable)
    instance Message ToggleLayout

    toggleLayouts :: (LayoutClass lt a, LayoutClass lf a) => lt a -> lf a -> ToggleLayouts lt lf a
    toggleLayouts = ToggleLayouts False

    instance (LayoutClass lt a, LayoutClass lf a) => LayoutClass (ToggleLayouts lt lf) a where
        runLayout (Workspace i (ToggleLayouts True lt lf) ms) r = do (ws,mlt') <- runLayout (Workspace i lt ms) r
                                                                     return (ws,fmap (\lt' -> ToggleLayouts True lt' lf) mlt')

        runLayout (Workspace i (ToggleLayouts False lt lf) ms) r = do (ws,mlf') <- runLayout (Workspace i lf ms) r
                                                                      return (ws,fmap (\lf' -> ToggleLayouts False lt lf') mlf')
        description (ToggleLayouts True lt _) = description lt
        description (ToggleLayouts False _ lf) = description lf
        handleMessage (ToggleLayouts bool lt lf) m
            | Just ReleaseResources <- fromMessage m =
                                       do mlf' <- handleMessage lf m
                                          mlt' <- handleMessage lt m
                                          return $ case (mlt',mlf') of
                                              (Nothing ,Nothing ) -> Nothing
                                              (Just lt',Nothing ) -> Just $ ToggleLayouts bool lt' lf
                                              (Nothing ,Just lf') -> Just $ ToggleLayouts bool lt lf'
                                              (Just lt',Just lf') -> Just $ ToggleLayouts bool lt' lf'
        handleMessage (ToggleLayouts True lt lf) m
            | Just ToggleLayout <- fromMessage m = do mlt' <- handleMessage lt (SomeMessage Hide)
                                                      let lt' = maybe lt id mlt'
                                                      return $ Just $ ToggleLayouts False lt' lf
            | Just (Toggle d) <- fromMessage m,
              d == description lt || d == description lf =
                  do mlt' <- handleMessage lt (SomeMessage Hide)
                     let lt' = maybe lt id mlt'
                     return $ Just $ ToggleLayouts False lt' lf
            | otherwise = do mlt' <- handleMessage lt m
                             return $ fmap (\lt' -> ToggleLayouts True lt' lf) mlt'
        handleMessage (ToggleLayouts False lt lf) m
            | Just ToggleLayout <- fromMessage m = do mlf' <- handleMessage lf (SomeMessage Hide)
                                                      let lf' = maybe lf id mlf'
                                                      return $ Just $ ToggleLayouts True lt lf'
            | Just (Toggle d) <- fromMessage m,
              d == description lt || d == description lf =
                  do mlf' <- handleMessage lf (SomeMessage Hide)
                     let lf' = maybe lf id mlf'
                     return $ Just $ ToggleLayouts True lt lf'
            | otherwise = do mlf' <- handleMessage lf m
                             return $ fmap (\lf' -> ToggleLayouts False lt lf') mlf'