{-# LANGUAGE TemplateHaskell #-}
module Vgrep.Widget.HorizontalSplit.Internal (
    -- * Split-view widget state
      HSplit (..)
    , Layout (..)
    , Focus (..)

    -- ** Auto-generated lenses
    , leftWidget
    , rightWidget
    , layout

    -- ** Additional lenses
    , currentWidget
    , leftWidgetFocused
    , rightWidgetFocused

    -- ** Re-exports
    , (%)
    ) where

import Control.Lens.Compat
import Data.Ratio          ((%))


-- $setup
-- >>> :set -fno-warn-missing-fields

-- | The internal state of the split-view widget. Tracks the state of both
-- child widgets and the current layout.
data HSplit s t = HSplit
    { _leftWidget  :: s
    -- ^ State of the left widget

    , _rightWidget :: t
    -- ^ State of the right widget

    , _layout      :: Layout
    -- ^ Current layout
    }

data Focus = FocusLeft | FocusRight deriving (Eq)
data Layout = LeftOnly | RightOnly | Split Focus Rational deriving (Eq)

makeLenses ''HSplit


-- | The currently focused child widget
--
-- >>> view currentWidget $ HSplit { _leftWidget = "foo", _layout = LeftOnly }
-- Left "foo"
currentWidget :: Lens' (HSplit s t) (Either s t)
currentWidget = lens getCurrentWidget setCurrentWidget
  where
    getCurrentWidget state = case view layout state of
        LeftOnly           -> Left  (view leftWidget  state)
        Split FocusLeft _  -> Left  (view leftWidget  state)
        RightOnly          -> Right (view rightWidget state)
        Split FocusRight _ -> Right (view rightWidget state)

    setCurrentWidget state newWidget = case (view layout state, newWidget) of
        (RightOnly,          Left  widgetL) -> set leftWidget  widgetL state
        (Split FocusLeft _,  Left  widgetL) -> set leftWidget  widgetL state
        (LeftOnly,           Right widgetR) -> set rightWidget widgetR state
        (Split FocusRight _, Right widgetR) -> set rightWidget widgetR state
        (_,                  _            ) -> state

-- | Traverses the left widget if focused
--
-- >>> has leftWidgetFocused $ HSplit { _layout = LeftOnly }
-- True
--
-- >>> has leftWidgetFocused $ HSplit { _layout = RightOnly }
-- False
--
-- >>> has leftWidgetFocused $ HSplit { _layout = Split FocusLeft (1 % 2) }
-- True
leftWidgetFocused :: Traversal' (HSplit s t) s
leftWidgetFocused = currentWidget . _Left

-- | Traverses the right widget if focused
--
-- >>> has rightWidgetFocused $ HSplit { _layout = RightOnly }
-- True
--
-- >>> has rightWidgetFocused $ HSplit { _layout = LeftOnly }
-- False
--
-- >>> has rightWidgetFocused $ HSplit { _layout = Split FocusRight (1 % 2) }
-- True
rightWidgetFocused :: Traversal' (HSplit s t) t
rightWidgetFocused = currentWidget . _Right