content: module Widgets.Menu where
  import Commons
  import qualified Widgets.Pane as Pane
  import qualified Widgets.Tab as Tab
  import qualified Widgets.Entry as Entry
  
  import Control.Lens
  import Data.Char (toUpper)
  import System.FilePath (takeFileName)
  import Brick.Widgets.Core ((<+>), str, hLimit, hBox, clickable)
  import Brick.Types (Widget)
  import Brick.Widgets.Border (borderWithLabel, border)
  import Graphics.Vty (Event(EvKey), Key(..), Modifier(MCtrl))
  
  data Menu = Menu {_clipboard :: Clipboard, _menuType :: MenuType}
  data MenuType = Main | Selection | Tab | Pane
  data Clipboard = CopyBoard {_fromEntry :: Entry.Entry} | CutBoard {_fromEntry :: Entry.Entry} | EmptyBoard
  
  instance Show Clipboard where
    show EmptyBoard = " -empty- "
    show board = takeFileName $ board ^. fromEntry . Entry.path
  
  -- lenses
  clipboard :: Lens' Menu Clipboard
  clipboard = lens _clipboard (\menu x -> menu {_clipboard = x})
  
  menuType :: Lens' Menu MenuType
  menuType = lens _menuType (\menu x -> menu {_menuType = x})
  
  fromEntry :: Traversal' Clipboard Entry.Entry
  fromEntry = filtered (not . isEmpty) . lens _fromEntry (\board x -> board {_fromEntry = x})
  
  -- creation
  make :: Menu
  make = Menu {_clipboard = EmptyBoard, _menuType = Main}
  
  -- rendering
  render :: Menu -> Pane.Pane -> Widget Name
  render m = hBox . (views clipboard renderClipboard m :) . views menuType renderButtons m
  
  renderButtons :: MenuType -> Pane.Pane -> [Widget Name]
  renderButtons tp pane = map renderButton $ case tp of
    Main -> mainButtons
    Selection -> backButton : maybe [] selectionButtons (Pane.selectedEntry pane)
    Tab -> backButton : views Pane.currentTab tabButtons pane
    Pane -> backButton : paneButtons
  
  renderButton :: (Widget Name, Maybe String, Name) -> Widget Name
  renderButton (bContent, bLabel, bName) = clickable bName $ case bLabel of
    Just txt -> borderWithLabel (str txt) bContent
    Nothing -> border bContent
  
  mainButtons :: [(Widget Name, Maybe String, Name)]
  mainButtons = [
      (str "se" <+> keybindStr "l" <+> str "ection menu", Nothing, Button {keyBind = KChar 'l', withCtrl = False}),
      (str "t" <+> keybindStr "a" <+> str "b menu", Nothing, Button {keyBind = KChar 'a', withCtrl = False}),
      (keybindStr "p" <+> str "ane menu", Nothing, Button {keyBind = KChar 'p', withCtrl = False}),
      (keybindStr "q" <+> str "uit", Nothing, Button {keyBind = KChar 'q', withCtrl = False})
    ]
  
  selectionButtons :: Entry.Entry -> [(Widget Name, Maybe String, Name)]
  selectionButtons e
    | Entry.isDir e = anySelectionButtons ++ [(keybindStr "o" <+> str "pen in new tab", ctrlText 'o', Button {keyBind = KChar 'o', withCtrl = True})]
    | otherwise = anySelectionButtons
  
  anySelectionButtons :: [(Widget Name, Maybe String, Name)]
  anySelectionButtons = [
      (str "cut", ctrlText 'x', Button {keyBind = KChar 'x', withCtrl = True}),
      (str "copy", ctrlText 'c', Button {keyBind = KChar 'c', withCtrl = True}),
      (keybindStr "r" <+> str "ename", ctrlText 'r', Button {keyBind = KChar 'r', withCtrl = True}),
      (keybindStr "d" <+> str "elete", ctrlText 'd', Button {keyBind = KChar 'd', withCtrl = True}),
      (keybindStr "s" <+> str "how info", Nothing, Button {keyBind = KChar 's', withCtrl = False})
    ]
  
  tabButtons :: Tab.Tab -> [(Widget Name, Maybe String, Name)]
  tabButtons tab
    | Tab.isDir tab = dirTabButtons ++ entryTabButtons orderType ++ anyTabButtons
    | Tab.isSearch tab = entryTabButtons orderType ++ anyTabButtons
    | otherwise = anyTabButtons
    where (Just orderType) = preview Tab.orderType tab
  
  dirTabButtons :: [(Widget Name, Maybe String, Name)]
  dirTabButtons = [
      (str "paste", ctrlText 'v', Button {keyBind = KChar 'v', withCtrl = True}),
      (keybindStr "s" <+> str "earch", ctrlText 's', Button {keyBind = KChar 's', withCtrl = True}),
      (keybindStr "m" <+> str "ake dir", Nothing, Button {keyBind = KChar 'm', withCtrl = False}),
      (keybindStr "t" <+> str "ouch file", Nothing, Button {keyBind = KChar 't', withCtrl = False})
    ]
  
  entryTabButtons :: Tab.OrderType -> [(Widget Name, Maybe String, Name)]
  entryTabButtons orderType = [
      (keybindStr "r" <+> str "efresh", Nothing, Button {keyBind = KChar 'r', withCtrl = False}),
      (keybindStr "o" <+> str ("rder by " ++ show (Tab.nextOrderType orderType)), Nothing, Button {keyBind = KChar 'o', withCtrl = False}),
      (keybindStr "i" <+> str "nvert order", Nothing, Button {keyBind = KChar 'i', withCtrl = False})
    ]
  
  anyTabButtons :: [(Widget Name, Maybe String, Name)]
  anyTabButtons = [
      (keybindStr "g" <+> str "o to", Nothing, Button {keyBind = KChar 'g', withCtrl = False}),
      (keybindStr "e" <+> str "mpty tab", Nothing, Button {keyBind = KChar 'e', withCtrl = False}),
      (keybindStr "k" <+> str "ill tab", Nothing, Button {keyBind = KChar 'k', withCtrl = False})
    ]
  
  paneButtons :: [(Widget Name, Maybe String, Name)]
  paneButtons = [
      (keybindStr "e" <+> str "mpty pane", ctrlText 'e', Button {keyBind = KChar 'e', withCtrl = True}),
      (keybindStr "k" <+> str "ill pane", ctrlText 'k', Button {keyBind = KChar 'k', withCtrl = True})
    ]
  
  ctrlText :: Char -> Maybe String
  ctrlText c = Just $ "C-" ++ [toUpper c]
  
  backButton :: (Widget Name, Maybe String, Name)
  backButton = (str "<_", Nothing, Button {keyBind = KBS, withCtrl = False})
  
  renderClipboard :: Clipboard -> Widget Name
  renderClipboard = hLimit 24 . borderWithLabel (str "clipboard") . str . show
  
  -- utility
  isEmpty :: Clipboard -> Bool
  isEmpty EmptyBoard = True
  isEmpty _ = False
  
  isCopy :: Clipboard -> Bool
  isCopy CopyBoard {} = True
  isCopy _ = False
  
  isCut :: Clipboard -> Bool
  isCut CutBoard {} = True
  isCut _ = False