content: {-# LANGUAGE RankNTypes #-}
  module Matterhorn.Events.MessageInterface
    ( handleMessageInterfaceEvent
    , messageInterfaceKeyHandlers
    , extraEditorKeyHandlers
    )
  where
  
  import           Prelude ()
  import           Matterhorn.Prelude
  
  import           Brick ( BrickEvent(VtyEvent) )
  import           Brick.Keybindings
  import           Brick.Widgets.Edit ( handleEditorEvent )
  
  import qualified Graphics.Vty as Vty
  import           Lens.Micro.Platform ( Lens' )
  import           Network.Mattermost.Types ( TeamId )
  
  import           Matterhorn.Types
  import           Matterhorn.Events.SaveAttachmentWindow
  import           Matterhorn.Events.ManageAttachments
  import           Matterhorn.Events.MessageSelect
  import           Matterhorn.Events.UrlSelect
  import           Matterhorn.State.Attachments
  import           Matterhorn.State.Editing
  import           Matterhorn.State.UrlSelect
  import           Matterhorn.State.MessageSelect
  import           Matterhorn.State.Channels
  
  
  handleMessageInterfaceEvent :: TeamId
                              -> Lens' ChatState (MessageInterface Name i)
                              -> Vty.Event
                              -> MH Bool
  handleMessageInterfaceEvent tId which ev = do
      mode <- use (which.miMode)
      case mode of
          Compose ->
              handleEventWith [ mhHandleKeyboardEvent (extraEditorKeybindings which)
                              , mhHandleKeyboardEvent (messageInterfaceKeybindings which)
                              , \e -> do
                                  case e of
                                      (Vty.EvPaste bytes) -> handlePaste (which.miEditor) bytes
                                      _ -> handleEditingInput (which.miEditor) e
                                  return True
                              ] ev
          MessageSelect ->
              onEventMessageSelect tId which ev
          ShowUrlList ->
              onEventUrlSelect which ev
          SaveAttachment {} ->
              onEventSaveAttachmentWindow which ev
          ManageAttachments ->
              onEventAttachmentList which ev
          BrowseFiles ->
              onEventBrowseFile which ev
  
  messageInterfaceKeybindings :: Lens' ChatState (MessageInterface n i)
                              -> KeyConfig KeyEvent
                              -> KeyDispatcher KeyEvent MH
  messageInterfaceKeybindings which kc =
      unsafeKeyDispatcher kc (messageInterfaceKeyHandlers which)
  
  messageInterfaceKeyHandlers :: Lens' ChatState (MessageInterface n i)
                              -> [MHKeyEventHandler]
  messageInterfaceKeyHandlers which =
      [ onEvent EnterSelectModeEvent
          "Select a message to edit/reply/delete" $
          beginMessageSelect which
  
      , onEvent PageUpEvent "Page up in the message list (enters message select mode)" $ do
          beginMessageSelect which
  
      , onEvent SelectOldestMessageEvent "Scroll to top of message list" $ do
          beginMessageSelect which
          messageSelectFirst which
  
      , onEvent EnterOpenURLModeEvent "Select and open a URL from the current message list" $
          startUrlSelect which
      ]
  
  extraEditorKeybindings :: Lens' ChatState (MessageInterface Name i)
                         -> KeyConfig KeyEvent
                         -> KeyDispatcher KeyEvent MH
  extraEditorKeybindings which kc =
      unsafeKeyDispatcher kc (extraEditorKeyHandlers which)
  
  extraEditorKeyHandlers :: Lens' ChatState (MessageInterface Name i)
                         -> [MHKeyEventHandler]
  extraEditorKeyHandlers which =
      let editWhich :: Lens' ChatState (EditState Name)
          editWhich = which.miEditor
      in [ onEvent ToggleMultiLineEvent "Toggle multi-line message compose mode" $
                toggleMultilineEditing editWhich
  
         , onEvent CancelEvent "Cancel autocomplete, message reply, or edit, in that order" $
              cancelAutocompleteOrReplyOrEdit editWhich
  
         , onEvent
             InvokeEditorEvent
             "Invoke `$EDITOR` to edit the current message" $
             invokeExternalEditor editWhich
  
         , onKey (bind '\t')
              "Tab-complete forward" $
              tabComplete editWhich Forwards
  
         , onKey (bind Vty.KBackTab)
              "Tab-complete backward" $
              tabComplete editWhich Backwards
  
         , onEvent ShowAttachmentListEvent "Show the attachment list" $
              showAttachmentList which
  
         , onKey (bind Vty.KEnter)
              "Send the current message" $ do
                  isMultiline <- use (editWhich.esEphemeral.eesMultiline)
                  case isMultiline of
                      -- Normally, this event causes the current message to
                      -- be sent. But in multiline mode we want to insert a
                      -- newline instead.
                      True -> handleEditingInput editWhich (Vty.EvKey Vty.KEnter [])
                      False -> do
                          content <- getEditorContent editWhich
                          handleInputSubmission editWhich content
  
         , onEvent
             ScrollUpEvent
             "Scroll up in the channel input history" $ do
                  -- Up in multiline mode does the usual thing; otherwise we
                  -- navigate the history.
                  isMultiline <- use (editWhich.esEphemeral.eesMultiline)
                  case isMultiline of
                      True -> mhZoom (editWhich.esEditor) handleEditorEvent
                                                (VtyEvent $ Vty.EvKey Vty.KUp [])
                      False -> inputHistoryBackward which
  
         , onEvent
             ScrollDownEvent
             "Scroll down in the channel input history" $ do
                  -- Down in multiline mode does the usual thing; otherwise
                  -- we navigate the history.
                  isMultiline <- use (editWhich.esEphemeral.eesMultiline)
                  case isMultiline of
                      True -> mhZoom (editWhich.esEditor) handleEditorEvent
                                                (VtyEvent $ Vty.EvKey Vty.KDown [])
                      False -> inputHistoryForward which
  
         , onEvent
             ReplyRecentEvent "Reply to the most recent message" $
             replyToLatestMessage which
         ]
  
  