{-|
Module: Types

Core data types for the RESTman TUI.

'AppS' is the top-level application state.  It is threaded through the Brick event loop and
holds all mutable information: the focused widget, editor contents, the HTTP connection
manager, and the last rendered response image.

'AppR' is the resource name type used to identify named Brick widgets (editors, viewports,
etc.).

See also 'Lib' for the functions that manipulate these types.
-}
module Types
    ( -- * Global Types for TUI manipulation
      AppS(..)
    , OverlayS(..)
    , AppR(..)
    , CustomHeaderR(..)
    , CustomHeaderColumn(..)
      -- * Range Ord-like types and helpers
    , RangeInAlign(..)
    , VertAlign
    , WideAlign
    , left
    , top
    ) where


-- brick
import Brick.Types (Extent)
import Brick.Widgets.Edit (Editor)
import Brick.Widgets.List (List)

-- bytestring
import qualified Data.ByteString.Lazy as Lazy (ByteString)

-- http-client
import qualified Network.HTTP.Client as HC

-- text
import Data.Text (Text)

-- vty
import Graphics.Vty.Image (Image)

-- internal imports
import HTTP.Client (Header, Method)

{-|
Application State

Single URL editor widget.

Widget names are all 'Text' values.
-}
data AppS = AppS
  { AppS -> AppR
focus :: AppR -- ^ Focus tracking within the main interface.
  , AppS -> Editor Method AppR
methodEditor :: !(Editor Method AppR) -- ^ text entry for the HTTP method to use for request
  , AppS -> Maybe OverlayS
overlayState :: !(Maybe OverlayS) -- ^ If not Nothing, the overlay is displayed with this state
  , AppS -> Editor Method AppR
urlEditor :: !(Editor String AppR) -- ^ text entry for URL to request
  , AppS -> Image
lastResponse :: !Image -- ^ Either the response body, or an error message
  , AppS -> Bool
useDefaultHeaders :: !Bool -- ^ If False, replace with; otherwise append custom headers
  , AppS -> [(Bool, Header)]
customHeaders :: ![(Bool, Header)] -- ^ additional/replacement request headers, and active flag
  , AppS -> Maybe (Editor Text AppR)
headerEditor :: !(Maybe (Editor Text AppR)) -- ^ When a custom header name or value is being edited, non-Nothing
  , AppS -> Maybe ByteString
payload :: !(Maybe Lazy.ByteString) -- ^ just the request body, no content type / filename
  , AppS -> Manager
connManager :: !HC.Manager -- ^ HTTP connection manager
  }

{-|
State of the UI overlay, which is currently just the "pop-up" for the method selector.
-}
data OverlayS = OverlayS
  { OverlayS -> Extent AppR
methodEditorExtent :: Extent AppR -- ^ Where the pop-up should start
  , OverlayS -> List AppR Method
methodList :: List AppR Method -- ^ Method selection
  }

-- | Application Resource Name — identifies every named widget in the Brick widget tree.
data AppR
  = MethodEditor       -- ^ The single-line editor for the HTTP method string.
  | UrlEditor          -- ^ The single-line editor for the target URL.
  | DefaultHeadersToggle -- ^ The checkbox-like widget for toggling default header use.
  | ExistingCustomHeader CustomHeaderR -- ^ One cell within the custom-headers table.
  | AddCustomHeader    -- ^ The @+@ button that creates a new custom header row.
  | ResponseBodyView   -- ^ The scrollable viewport that shows the response body.
  | MethodSelector     -- ^ The pop-up list used to pick an HTTP method.
  deriving (AppR -> AppR -> Bool
(AppR -> AppR -> Bool) -> (AppR -> AppR -> Bool) -> Eq AppR
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AppR -> AppR -> Bool
== :: AppR -> AppR -> Bool
$c/= :: AppR -> AppR -> Bool
/= :: AppR -> AppR -> Bool
Eq, Eq AppR
Eq AppR =>
(AppR -> AppR -> Ordering)
-> (AppR -> AppR -> Bool)
-> (AppR -> AppR -> Bool)
-> (AppR -> AppR -> Bool)
-> (AppR -> AppR -> Bool)
-> (AppR -> AppR -> AppR)
-> (AppR -> AppR -> AppR)
-> Ord AppR
AppR -> AppR -> Bool
AppR -> AppR -> Ordering
AppR -> AppR -> AppR
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: AppR -> AppR -> Ordering
compare :: AppR -> AppR -> Ordering
$c< :: AppR -> AppR -> Bool
< :: AppR -> AppR -> Bool
$c<= :: AppR -> AppR -> Bool
<= :: AppR -> AppR -> Bool
$c> :: AppR -> AppR -> Bool
> :: AppR -> AppR -> Bool
$c>= :: AppR -> AppR -> Bool
>= :: AppR -> AppR -> Bool
$cmax :: AppR -> AppR -> AppR
max :: AppR -> AppR -> AppR
$cmin :: AppR -> AppR -> AppR
min :: AppR -> AppR -> AppR
Ord, Int -> AppR -> ShowS
[AppR] -> ShowS
AppR -> Method
(Int -> AppR -> ShowS)
-> (AppR -> Method) -> ([AppR] -> ShowS) -> Show AppR
forall a.
(Int -> a -> ShowS) -> (a -> Method) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AppR -> ShowS
showsPrec :: Int -> AppR -> ShowS
$cshow :: AppR -> Method
show :: AppR -> Method
$cshowList :: [AppR] -> ShowS
showList :: [AppR] -> ShowS
Show)

{-|
Resource name for a single cell in the custom-headers table.

'listIndex' selects the row (0-based index into 'customHeaders' of 'AppS') and 'column'
selects which of the three cells in that row has focus.
-}
data CustomHeaderR = MkCustomHeaderR
  { CustomHeaderR -> Int
listIndex :: !Int -- ^ target in 'customHeaders' from 'AppS'
  , CustomHeaderR -> CustomHeaderColumn
column :: !CustomHeaderColumn
  }
  deriving (CustomHeaderR -> CustomHeaderR -> Bool
(CustomHeaderR -> CustomHeaderR -> Bool)
-> (CustomHeaderR -> CustomHeaderR -> Bool) -> Eq CustomHeaderR
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CustomHeaderR -> CustomHeaderR -> Bool
== :: CustomHeaderR -> CustomHeaderR -> Bool
$c/= :: CustomHeaderR -> CustomHeaderR -> Bool
/= :: CustomHeaderR -> CustomHeaderR -> Bool
Eq, Eq CustomHeaderR
Eq CustomHeaderR =>
(CustomHeaderR -> CustomHeaderR -> Ordering)
-> (CustomHeaderR -> CustomHeaderR -> Bool)
-> (CustomHeaderR -> CustomHeaderR -> Bool)
-> (CustomHeaderR -> CustomHeaderR -> Bool)
-> (CustomHeaderR -> CustomHeaderR -> Bool)
-> (CustomHeaderR -> CustomHeaderR -> CustomHeaderR)
-> (CustomHeaderR -> CustomHeaderR -> CustomHeaderR)
-> Ord CustomHeaderR
CustomHeaderR -> CustomHeaderR -> Bool
CustomHeaderR -> CustomHeaderR -> Ordering
CustomHeaderR -> CustomHeaderR -> CustomHeaderR
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: CustomHeaderR -> CustomHeaderR -> Ordering
compare :: CustomHeaderR -> CustomHeaderR -> Ordering
$c< :: CustomHeaderR -> CustomHeaderR -> Bool
< :: CustomHeaderR -> CustomHeaderR -> Bool
$c<= :: CustomHeaderR -> CustomHeaderR -> Bool
<= :: CustomHeaderR -> CustomHeaderR -> Bool
$c> :: CustomHeaderR -> CustomHeaderR -> Bool
> :: CustomHeaderR -> CustomHeaderR -> Bool
$c>= :: CustomHeaderR -> CustomHeaderR -> Bool
>= :: CustomHeaderR -> CustomHeaderR -> Bool
$cmax :: CustomHeaderR -> CustomHeaderR -> CustomHeaderR
max :: CustomHeaderR -> CustomHeaderR -> CustomHeaderR
$cmin :: CustomHeaderR -> CustomHeaderR -> CustomHeaderR
min :: CustomHeaderR -> CustomHeaderR -> CustomHeaderR
Ord, Int -> CustomHeaderR -> ShowS
[CustomHeaderR] -> ShowS
CustomHeaderR -> Method
(Int -> CustomHeaderR -> ShowS)
-> (CustomHeaderR -> Method)
-> ([CustomHeaderR] -> ShowS)
-> Show CustomHeaderR
forall a.
(Int -> a -> ShowS) -> (a -> Method) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CustomHeaderR -> ShowS
showsPrec :: Int -> CustomHeaderR -> ShowS
$cshow :: CustomHeaderR -> Method
show :: CustomHeaderR -> Method
$cshowList :: [CustomHeaderR] -> ShowS
showList :: [CustomHeaderR] -> ShowS
Show)

-- | Which column of a custom-header row has focus.
data CustomHeaderColumn
  = ActiveToggle -- ^ The enabled/disabled checkbox column.
  | NameEditor   -- ^ The header-name editor column.
  | ValueEditor  -- ^ The header-value editor column.
  deriving (CustomHeaderColumn -> CustomHeaderColumn -> Bool
(CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> (CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> Eq CustomHeaderColumn
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
== :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
$c/= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
/= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
Eq, Eq CustomHeaderColumn
Eq CustomHeaderColumn =>
(CustomHeaderColumn -> CustomHeaderColumn -> Ordering)
-> (CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> (CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> (CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> (CustomHeaderColumn -> CustomHeaderColumn -> Bool)
-> (CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn)
-> (CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn)
-> Ord CustomHeaderColumn
CustomHeaderColumn -> CustomHeaderColumn -> Bool
CustomHeaderColumn -> CustomHeaderColumn -> Ordering
CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: CustomHeaderColumn -> CustomHeaderColumn -> Ordering
compare :: CustomHeaderColumn -> CustomHeaderColumn -> Ordering
$c< :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
< :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
$c<= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
<= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
$c> :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
> :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
$c>= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
>= :: CustomHeaderColumn -> CustomHeaderColumn -> Bool
$cmax :: CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn
max :: CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn
$cmin :: CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn
min :: CustomHeaderColumn -> CustomHeaderColumn -> CustomHeaderColumn
Ord, Int -> CustomHeaderColumn -> ShowS
[CustomHeaderColumn] -> ShowS
CustomHeaderColumn -> Method
(Int -> CustomHeaderColumn -> ShowS)
-> (CustomHeaderColumn -> Method)
-> ([CustomHeaderColumn] -> ShowS)
-> Show CustomHeaderColumn
forall a.
(Int -> a -> ShowS) -> (a -> Method) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CustomHeaderColumn -> ShowS
showsPrec :: Int -> CustomHeaderColumn -> ShowS
$cshow :: CustomHeaderColumn -> Method
show :: CustomHeaderColumn -> Method
$cshowList :: [CustomHeaderColumn] -> ShowS
showList :: [CustomHeaderColumn] -> ShowS
Show)

-- | Alignment of one range strictly within another range both over a discete, totally ordered set.
data RangeInAlign
  = Min -- ^ min of both ranges match
  | MidL -- ^ inner midpoint as close as possible to, but less than or equal to outer midpoint
  | MidG -- ^ inner midpoint as close as possible to, but greater than or equal to outer midpoint
  | Max -- ^ max of both ranges match
  deriving (RangeInAlign -> RangeInAlign -> Bool
(RangeInAlign -> RangeInAlign -> Bool)
-> (RangeInAlign -> RangeInAlign -> Bool) -> Eq RangeInAlign
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RangeInAlign -> RangeInAlign -> Bool
== :: RangeInAlign -> RangeInAlign -> Bool
$c/= :: RangeInAlign -> RangeInAlign -> Bool
/= :: RangeInAlign -> RangeInAlign -> Bool
Eq, Eq RangeInAlign
Eq RangeInAlign =>
(RangeInAlign -> RangeInAlign -> Ordering)
-> (RangeInAlign -> RangeInAlign -> Bool)
-> (RangeInAlign -> RangeInAlign -> Bool)
-> (RangeInAlign -> RangeInAlign -> Bool)
-> (RangeInAlign -> RangeInAlign -> Bool)
-> (RangeInAlign -> RangeInAlign -> RangeInAlign)
-> (RangeInAlign -> RangeInAlign -> RangeInAlign)
-> Ord RangeInAlign
RangeInAlign -> RangeInAlign -> Bool
RangeInAlign -> RangeInAlign -> Ordering
RangeInAlign -> RangeInAlign -> RangeInAlign
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: RangeInAlign -> RangeInAlign -> Ordering
compare :: RangeInAlign -> RangeInAlign -> Ordering
$c< :: RangeInAlign -> RangeInAlign -> Bool
< :: RangeInAlign -> RangeInAlign -> Bool
$c<= :: RangeInAlign -> RangeInAlign -> Bool
<= :: RangeInAlign -> RangeInAlign -> Bool
$c> :: RangeInAlign -> RangeInAlign -> Bool
> :: RangeInAlign -> RangeInAlign -> Bool
$c>= :: RangeInAlign -> RangeInAlign -> Bool
>= :: RangeInAlign -> RangeInAlign -> Bool
$cmax :: RangeInAlign -> RangeInAlign -> RangeInAlign
max :: RangeInAlign -> RangeInAlign -> RangeInAlign
$cmin :: RangeInAlign -> RangeInAlign -> RangeInAlign
min :: RangeInAlign -> RangeInAlign -> RangeInAlign
Ord, Int -> RangeInAlign -> ShowS
[RangeInAlign] -> ShowS
RangeInAlign -> Method
(Int -> RangeInAlign -> ShowS)
-> (RangeInAlign -> Method)
-> ([RangeInAlign] -> ShowS)
-> Show RangeInAlign
forall a.
(Int -> a -> ShowS) -> (a -> Method) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RangeInAlign -> ShowS
showsPrec :: Int -> RangeInAlign -> ShowS
$cshow :: RangeInAlign -> Method
show :: RangeInAlign -> Method
$cshowList :: [RangeInAlign] -> ShowS
showList :: [RangeInAlign] -> ShowS
Show)

-- | Vertical alignment
type VertAlign = RangeInAlign

top{-, centerHigh, centerLow, bottom-} :: VertAlign

-- | Align at the top, matching min vert corodinates.
top :: RangeInAlign
top = RangeInAlign
Min
{-
centerHigh = MidL
centerLow = MidG
bottom = Max
-}

-- | Wide-ways ("horizonal") alignment
type WideAlign = RangeInAlign
left{-, centerLeft, centerRight, right-} :: VertAlign

-- | Align on the left, matching min wide coordinates.
left :: RangeInAlign
left = RangeInAlign
Min
{-
centerLeft = MidL
centerRight = MidG
right = Max
-}