{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-- | Configuration with defaults I like and brightness adjustable for my computer and appropriate
module XMonad.Config.Vanessa (vConfig) where

import qualified Data.Map                  as M
import           Data.Maybe
import           Data.Monoid
import           Data.Ratio                ((%))
import           System.IO                 (Handle)
import           XMonad                    hiding (workspaces)
import           XMonad.Actions.GridSelect
import           XMonad.Hooks.DynamicLog
import           XMonad.Hooks.ManageDocks
import           XMonad.Layout.Fullscreen
import           XMonad.Layout.Hidden
import           XMonad.Layout.Mosaic
import           XMonad.Layout.Reflect
import           XMonad.Layout.Spiral
import           XMonad.StackSet           hiding (float)
import           XMonad.Util.Brightness
import           XMonad.Util.Keyboard
import           XMonad.Util.MediaKeys
import           XMonad.Util.NamedWindows
import           XMonad.Util.Run
import           XMonad.Util.Volume

-- | IO action of the whole thing
vConfig :: IO ()
vConfig = xmonad . config' =<< spawnPipe "xmobar"
    where config' = myConfig

-- | Custom configuration taking in one pipe to xmobar
myConfig xmproc = fullscreenSupport $ docks $ def { terminal   = "alacritty"
                              , keys       = newKeys
                              , layoutHook = myLayout
                              , logHook    = vLogHook xmproc
                              , manageHook = myManageHook <+> manageDocks
                              , handleEventHook = docksEventHook
                              , startupHook = docksStartupHook }

-- | get the current music playing (assumed to be in number 5)
musicString :: X String
musicString = do
    winset <- gets windowset
    {-- let p = (== "5") . fst --}
    wt <- maybe (pure "") (fmap show . getName) . fmap snd . listToMaybe {--. filter p--} $ zip ((map tag . workspaces) winset) (allWindows winset)
    pure . xmobarColor "green" "black" . take 40 $ wt

-- | Provides custom hooks to xmonad. This disables printing the window title/connects xmobar and xmonad.
vLogHook :: Handle -> X ()
vLogHook xmproc = musicString >>= \m -> dynamicLogWithPP xmobarPP { ppOutput = hPutStrLn xmproc
                                                                  , ppTitle = const m
                                                                  , ppLayout = const ""
                                                                  , ppHiddenNoWindows = id
                                                                  , ppHidden = xmobarColor "darkorange" "black" -- . (\x -> if x == "5" then "Spotify" else x)
                                                                  , ppVisible = xmobarColor "yellow" "black"
                                                                  }

-- | Doesn't work on spotify
myManageHook :: Query (Endo WindowSet)
myManageHook = composeAll [ className =? "Gimp-2.8"                            --> doFloat
                          , resource =? "spotify"                              --> doF (shift "5")
                          , className =? "Firefox"                             --> doF (shift "5")
                          , className =? "google-chrome"                       --> doF (shift "3")
                          , resource =? "crx_bikioccmkafdpakkkcpdbppfkghcmihk" --> doF (shift "7")
                          , resource =? "crx_bgkodfmeijboinjdegggmkbkjfiagaan" --> doF (shift "7")
                          , resource =? "launcher"                             --> doFloat
                          , resource =? "qemu-system-arm"                      --> doFloat
                          , className =? "libreoffice-writer"                  --> doFloat
                          , className =? "Gimp"                                --> doFloat
                          , className =? "keepassx"                            --> doFloat
                          , className =? "xviewer"                             --> doFloat
                          , className =? "qemu-system-x86_64"                  --> doFloat
                          ]

-- TODO gaps between windows?

mkSmall :: Window -> X ()
mkSmall = flip tileWindow (Rectangle 850 150 600 400)

-- | Custom keymaps to adjust volume, brightness, and
myKeys :: XConfig t -> M.Map (KeyMask, KeySym) (X ())
myKeys XConfig {XMonad.modMask = modm} = mediaKeys . M.fromList $
             [ --volume control
               ((modm, xK_Up), raiseVolume (5 :: Word))
             , ((modm, xK_Down), lowerVolume (5 :: Word))
             , ((modm, xK_Delete), toggleMute)
             --personal (extra) media keys
             , ((modm, xK_Page_Down), audioNext)
             , ((modm, xK_Page_Up), audioPrev)
             , ((modm, xK_Home), audioPlayPause)
             --brightness
             , ((modm, xK_Left), brighten (-100))
             , ((modm, xK_Right), brighten 100)
             --program shortcuts
             , ((modm, xK_q), spawn "spotify")
             , ((modm .|. shiftMask, xK_n), spawn "firefox")
             , ((modm .|. controlMask, xK_Return), spawn "gnome-terminal")
             --launch bar
             , ((modm, xK_p), spawn "yeganesh -x")
             --screenshots
             , ((0, xK_Print), spawn "cd ~/.screenshots && scrot")
             -- open scratchpad
             , ((modm .|. shiftMask, xK_p), withFocused (mconcat . sequence [float, mkSmall]))
             --shutdown etc.
             , ((modm .|. shiftMask, xK_End), spawn "shutdown now")
             -- lock screen
             , ((controlMask, xK_End), spawn "slock")
             --switch keyboards
             , ((modm, xK_F1), setLang def)
             , ((modm, xK_F2), setLang tibetan)
             , ((modm, xK_F3), setLang accented)
             , ((modm, xK_F4), setLang français)
             , ((modm, xK_F5), setLang deutsch)
             , ((modm, xK_F6), setLang anglisc)
             , ((modm, xK_F7), setLang dansk)
             , ((modm, xK_F9), setLang dzongkha)
             -- hide windows
             , ((modm .|. shiftMask, xK_h), withFocused (mconcat . sequence [hide, hideWindow]))
             , ((modm, xK_u), popNewestHiddenWindow >> withFocused reveal)
             -- grid select
             , ((modm, xK_g), goToSelected def)
             -- Mosaic adjustment
             , ((modm, xK_a), sendMessage Taller)
             , ((modm, xK_s), sendMessage Wider)
             , ((modm, xK_r), sendMessage Reset)
             ]

-- | Function giving keybindings to undo
keysToRemove :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
keysToRemove XConfig {XMonad.modMask = modm} = M.fromList
        [ ((modm, xK_p), pure ()) ]

-- | Gives a better ratio for the master pane and lets us spiral windows
myLayout = (avoidStruts . hiddenWindows $ mosaic 1.33 mosaicSettings ||| normalPanes ||| reflectHoriz normalPanes ||| Full) ||| hiddenWindows (spiral (6/7))
    where normalPanes = Tall 1 (3/100) (3/7)
          mosaicSettings = take 6 $ iterate (* (4 % 5)) 1

-- | Make new key layout from a given keyboard layout
newKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
newKeys x = myKeys x `M.union` (keys def x `M.difference` keysToRemove x)