content: module Matterhorn.Events.Mouse
    ( mouseHandlerByMode
    )
  where
  
  import           Prelude ()
  import           Matterhorn.Prelude
  
  import           Brick
  
  import           Network.Mattermost.Types ( TeamId )
  
  import           Matterhorn.State.Channels
  import           Matterhorn.State.Teams ( setTeam )
  import           Matterhorn.State.ListWindow ( listWindowActivate )
  import           Matterhorn.Types
  
  import           Matterhorn.Events.EditNotifyPrefs ( handleEditNotifyPrefsEvent )
  import           Matterhorn.Events.ChannelTopicWindow ( channelTopicWindowMouseHandler )
  import           Matterhorn.State.MessageSelect ( exitMessageSelect )
  import           Matterhorn.State.Reactions ( toggleReaction )
  import           Matterhorn.State.Links ( openLinkTarget )
  
  -- The top-level mouse click handler. This dispatches to specific
  -- handlers for some modes, or the global mouse handler when the mode is
  -- not important (or when it is important that we ignore the mode).
  mouseHandlerByMode :: TeamId -> Mode -> BrickEvent Name MHEvent -> MH ()
  mouseHandlerByMode tId mode =
      case mode of
          ChannelSelect            -> channelSelectMouseHandler tId
          EditNotifyPrefs          -> void . handleEditNotifyPrefsEvent tId
          ReactionEmojiListWindow -> reactionEmojiListMouseHandler tId
          ChannelTopicWindow       -> channelTopicWindowMouseHandler tId
          _                        -> globalMouseHandler tId
  
  -- Handle global mouse click events (when mode is not important).
  --
  -- Note that the handler for each case may need to check the application
  -- mode before handling the click. This is because some mouse events
  -- only make sense when the UI is displaying certain contents. While
  -- it's true that we probably wouldn't even get the click events in the
  -- first place (because the UI element would only cause a click event
  -- to be reported if it was actually rendered), there are cases when we
  -- can get clicks on UI elements that *are* clickable even though those
  -- clicks don't make sense for the application mode. A concrete example
  -- of this is when we display the current channel's contents in one
  -- layer, in monochrome, and then display a modal dialog box on top of
  -- that. We probably *should* ignore clicks on the lower layer because
  -- that's not the mode the application is in, but getting that right
  -- could be hard because we'd have to figure out all possible modes
  -- where those lower-layer clicks would be nonsensical. We don't bother
  -- doing that in the harder cases; instead we just handle the clicks
  -- and do what we would ordinarily do, assuming that there's no real
  -- harm done. The worst that could happen is that a user could click
  -- accidentally on a grayed-out URL (in a message, say) next to a modal
  -- dialog box and then see the URL get opened. That would be weird, but
  -- it isn't the end of the world.
  globalMouseHandler :: TeamId -> BrickEvent Name MHEvent -> MH ()
  globalMouseHandler tId (MouseDown n _ _ _) = do
      st <- use id
      case n of
          ClickableChannelListEntry channelId -> do
              whenMode tId Main $ do
                  resetReturnChannel tId
                  setFocus tId channelId
          ClickableTeamListEntry teamId ->
              -- We deliberately handle this event in all modes; this
              -- allows us to switch the UI to another team regardless of
              -- what state it is in, which is by design since all teams
              -- have their own UI states.
              setTeam teamId
          ClickableURL _ _ _ t ->
              void $ openLinkTarget t
          ClickableUsername _ _ _ username | username /= myUsername st -> do
              whenMode tId ViewMessage $ do
                  -- Pop view message mode
                  popMode tId
                  -- Exit message select for the focused interface,
                  -- since that is the only way we get into message
                  -- view mode and we want to reset the focused message
                  -- interface mode so that when we return to it from the
                  -- DM channel, it's not still stuck in message selection
                  -- mode.
                  foc <- use (csTeam(tId).tsMessageInterfaceFocus)
                  case foc of
                      FocusThread ->
                          exitMessageSelect $ unsafeThreadInterface tId
                      FocusCurrentChannel -> do
                          mcId <- use (csCurrentChannelId(tId))
                          case mcId of
                              Nothing -> return ()
                              Just cId -> exitMessageSelect $ csChannelMessageInterface cId
              changeChannelByName tId $ addUserSigil username
          ClickableAttachmentInMessage _ fId ->
              void $ openLinkTarget $ LinkFileId fId
          ClickableReaction pId _ t uIds ->
              void $ toggleReaction pId t uIds
          ClickableChannelListGroupHeading label ->
              toggleChannelListGroupVisibility label
          ClickableURLListEntry _ t ->
              void $ openLinkTarget t
          VScrollBar e vpName -> do
              let vp = viewportScroll vpName
              mh $ case e of
                  SBHandleBefore -> vScrollBy vp (-1)
                  SBHandleAfter  -> vScrollBy vp 1
                  SBTroughBefore -> vScrollPage vp Up
                  SBTroughAfter  -> vScrollPage vp Down
                  SBBar          -> return ()
          _ ->
              return ()
  globalMouseHandler _ _ =
      return ()
  
  channelSelectMouseHandler :: TeamId -> BrickEvent Name MHEvent -> MH ()
  channelSelectMouseHandler tId (MouseDown (ClickableChannelSelectEntry match) _ _ _) = do
      popMode tId
      setFocus tId $ channelListEntryChannelId $ matchEntry match
  channelSelectMouseHandler _ _ =
      return ()
  
  reactionEmojiListMouseHandler :: TeamId -> BrickEvent Name MHEvent -> MH ()
  reactionEmojiListMouseHandler tId (MouseDown (ClickableReactionEmojiListWindowEntry val) _ _ _) =
      listWindowActivate tId (csTeam(tId).tsReactionEmojiListWindow) val
  reactionEmojiListMouseHandler _ _ =
      return ()
  