-- Haskell libraries
import Data.Bits ((.|.))
import qualified Data.Map as M
import Data.Ratio
import IO
import Data.List
import Data.Maybe

-- XMonad Core
import XMonad hiding ((|||))
import XMonad.Operations
import qualified XMonad.StackSet as S
 
-- XMonad Contribs
-- Layouts
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Tabbed
import XMonad.Layout.IM
import XMonad.Layout.PerWorkspace
import XMonad.Layout.DecorationMadness
import XMonad.Layout.Grid
import XMonad.Layout.Decoration
import XMonad.Layout.Monitor
import XMonad.Layout.Column
import XMonad.Layout.TwoPane
import XMonad.Layout.ComboP
import XMonad.Layout.Named
-- Utils
import XMonad.Util.EZConfig
import XMonad.Util.Run (spawnPipe)
-- Actions
import XMonad.Actions.DwmPromote
import XMonad.Actions.CycleSelectedLayouts
import XMonad.Actions.UpdatePointer
import XMonad.Actions.GridSelect
import XMonad.Actions.SpawnOn
-- Hooks
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.FadeInactive
import XMonad.Hooks.SetWMName
-- Prompt
import XMonad.Prompt
import XMonad.Prompt.Shell

-- workspace names
wsMain = "1:main"
wsBook = "5:book"
wsIrc  = "6:irc"
wsGimp  = "7:gimp"
wsIm   = "8:im"
wsWeb  = "9:web"

wslist         = [wsMain, "2:work", "3:work", "4:work", wsBook, wsIrc, wsGimp, wsIm, wsWeb]
-- entry point
main = do
  sp <- mkSpawner
  xmonad $ defaultConfig
    { logHook            = dynamicLogWithPP myPP >> updatePointer (Relative 0.5 0.5)
    , workspaces         = wslist
    , layoutHook         = myLayouts
    , manageHook         = myManageHook <+> manageDocks <+> manageMonitor clock <+> manageSpawn sp
    , borderWidth        = 0
    , focusFollowsMouse  = True
    , startupHook        = setWMName "LG3D"
    } `additionalKeys` myKeys sp

-- custom keybindings; are added to defaults from Config.hs and can overwrite them
myKeys sp =
    [ ((0,        xK_F2    ), launch "exec xfce4-terminal")
    , ((mod4Mask, xK_r     ), launch "firefox http://www.google.com/reader")
    , ((mod4Mask, xK_o     ), launch "exec konqueror")
    , ((mod4Mask, xK_i     ), launch "exec firefox")
    , ((mod4Mask, xK_s     ), spawnOn sp wsIrc "xfce4-terminal -e irssi")
    , ((mod4Mask, xK_q     ), launch "cd ~/photo; exec gqview")
    , ((mod4Mask, xK_t     ), launch "exec xfce4-terminal -e mutt -T mutt")
    , ((mod4Mask, xK_g     ), launch "exec gvim")
    , ((mod4Mask, xK_z     ), xmms2 "prev")
    , ((mod4Mask, xK_x     ), xmms2 "play")
    , ((mod4Mask, xK_c     ), xmms2 "pause")
    , ((mod4Mask, xK_v     ), xmms2 "stop")
    , ((mod4Mask, xK_b     ), xmms2 "next")
    , ((mod4Mask, xK_Up    ), xmms2 "volume +5")
    , ((mod4Mask, xK_Down  ), xmms2 "volume -5")
    , ((mod1Mask, xK_p     ), spawn "sudo hibernate")
    , ((mod1Mask, xK_o     ), spawn "sudo hibernate-ram")
    , ((mod1Mask, xK_F4    ), kill)
    , ((mod1Mask, xK_Return), dwmpromote)
    , ((mod1Mask, xK_b     ), sendMessage ToggleStruts)
    , ((0,        xK_F4    ), shellPromptHere sp defaultXPConfig)
    , ((mod1Mask, xK_c     ), launch "gvim ~/.xmonad/xmonad.hs")
    , ((mod1Mask, xK_r     ), spawn "randr")
    , ((mod1Mask, xK_a     ), sendMessage NextLayout)
    , ((mod1Mask, xK_space ), cycleThroughLayouts ["Tabbed Simplest", "DefaultDecoration Grid"])
    , ((mod1Mask, xK_s     ), cycleThroughLayouts ["DefaultDecoration Mirror Tall", "DefaultDecoration Tall"])
    , ((mod1Mask, xK_g     ), goToSelected myGSconfig)
    , ((mod1Mask, xK_u     ), broadcastMessage ToggleMonitor >> refresh)
    , ((mod4Mask, xK_a     ), launch "firefox ~/my/tw/tw.html")
    ]
    ++
    [((m .|. mod1Mask, key), screenWorkspace sc >>= flip whenJust (windows . f))
        | (key, sc) <- zip [xK_e, xK_w] [0..]
        , (f, m) <- [(S.view, 0), (S.shift, shiftMask)]]

    where
    silent = spawn.("exec " ++).(++" > /dev/null")
    xmms2 = silent.("xmms2 "++)
    launch = spawnHere sp
    myGSconfig = defaultGSConfig { gs_colorizer = colorRangeFromClassName (0,100,100) (100,255,255) (255,127,127) (0,0,0) (0,0,0) }

-- available layouts
myLayouts = ModifiedLayout clock $
    avoidStruts $
    onWorkspace wsIm (withIM (1%7) ((ClassName "Tkabber") `Or` (Role "buddy_list")) $ tiled ||| Grid) $
    onWorkspace wsBook (myTabbed ||| Full )$
    onWorkspace wsGimp gimpLayout $
    tallDefault shrinkText myTabConfig |||
    myTabbed |||
    decoGrid |||
    mirrorTallDefault shrinkText myTabConfig
    where
        tiled   = Tall nmaster delta ratio
        nmaster = 1
        ratio   = 1/2
        delta   = 3/100
        decorate = decoration shrinkText myTabConfig DefaultDecoration
        decoGrid = decorate Grid
        myTabConfig = defaultTheme
            { activeColor         = "#333399"
            , activeBorderColor   = "#888888"
            , activeTextColor     = "#FFFFFF"
            , inactiveColor       = "#333344"
            , inactiveBorderColor = "#888888"
            , inactiveTextColor   = "#FFFFFF"
            , decoHeight          = 18
            }
        myTabbed = tabbed shrinkText myTabConfig

        gimpLayout = named "Gimp" $ split 0.65 gimpMain gimpTools (Role "gimp-image-window")
        gimpTools = split 0.5  decoGrid gimpDocks (Role "gimp-toolbox")
        gimpMain = decorate $ Column 1.6
        gimpDocks = decorate $ Column 1.6
        split x = combineTwoP (TwoPane 0.03 x)

-- configuration of DynamicLog (i.e. what xmobar shows)
myPP = defaultPP
    { ppCurrent = xmobarColor "yellow" ""
    , ppTitle   = const ""
    , ppVisible = xmobarColor "cyan" ""
    }

-- configuration of the clock monitor
clock = monitor
    { prop = ClassName "Cairo-clock" `And` Title "MacSlow's Cairo-Clock"
    , rect = (Rectangle (1280-150) (800-150) 150 150)
    , persistent = True
    , opacity = 0xAAAAAAAA
    }

-- rules for some programs
myManageHook = composeAll
    [ className =? "Chat"       --> moveTo wsIm
    , className =? "Kpdf"       --> moveTo wsBook
    , className =? "Kghostview" --> moveTo wsBook
    , className =? "Okular"     --> moveTo wsBook
    , className =? "Djview3"    --> moveTo wsBook
    , className =? "Xchat"      --> moveTo wsIrc
    , className =? "Tkabber"    --> moveTo wsIm
    , className =? "Eclipse"    --> moveTo "2:work"
    , flip fmap className (isPrefixOf "Gimp") --> moveTo wsGimp
    --, className =? "JuicyBar"   --> doF S.sink
    , isDialog --> doCenterFloat
    ]
    where moveTo = doF . S.shift

