module Ribosome.Menu.Action where

import Control.Lens (over, set)

import Ribosome.Data.List (indexesComplement)
import Ribosome.Menu.Data.Menu (Menu(Menu))
import qualified Ribosome.Menu.Data.Menu as Menu (marked, selected)
import Ribosome.Menu.Data.MenuConsumerAction (MenuConsumerAction)
import qualified Ribosome.Menu.Data.MenuConsumerAction as MenuConsumerAction (MenuConsumerAction(..))
import Ribosome.Menu.Prompt.Data.Prompt (Prompt)

menuContinue ::
  Applicative m =>
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuContinue :: Menu i -> m (MenuConsumerAction m a, Menu i)
menuContinue =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuConsumerAction m a
forall (m :: * -> *) a. MenuConsumerAction m a
MenuConsumerAction.Continue,)

menuExecute ::
  Applicative m =>
  m () ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuExecute :: m () -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuExecute m ()
thunk =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (m () -> MenuConsumerAction m a
forall (m :: * -> *) a. m () -> MenuConsumerAction m a
MenuConsumerAction.Execute m ()
thunk,)

menuRender ::
  Applicative m =>
  Bool ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuRender :: Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuRender Bool
changed =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> MenuConsumerAction m a
forall (m :: * -> *) a. Bool -> MenuConsumerAction m a
MenuConsumerAction.Render Bool
changed,)

menuQuit ::
  Applicative m =>
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuQuit :: Menu i -> m (MenuConsumerAction m a, Menu i)
menuQuit =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuConsumerAction m a
forall (m :: * -> *) a. MenuConsumerAction m a
MenuConsumerAction.Quit,)

menuQuitWith ::
  Applicative m =>
  m a ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuQuitWith :: m a -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuQuitWith m a
next =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (m a -> MenuConsumerAction m a
forall (m :: * -> *) a. m a -> MenuConsumerAction m a
MenuConsumerAction.QuitWith m a
next,)

menuReturn ::
  Applicative m =>
  a ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuReturn :: a -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuReturn a
a =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> MenuConsumerAction m a
forall (m :: * -> *) a. a -> MenuConsumerAction m a
MenuConsumerAction.Return a
a,)

menuFilter ::
  Applicative m =>
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuFilter :: Menu i -> m (MenuConsumerAction m a, Menu i)
menuFilter =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuConsumerAction m a
forall (m :: * -> *) a. MenuConsumerAction m a
MenuConsumerAction.Filter,)

menuCycle ::
  Monad m =>
  Int ->
  Menu i ->
  Prompt ->
  m (MenuConsumerAction m a, Menu i)
menuCycle :: Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle Int
offset m :: Menu i
m@(Menu [MenuItem i]
_ [FilteredMenuItem i]
filtered Int
_ [Int]
_ MenuFilter
_ Maybe Int
maxItems) Prompt
_ =
  Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuRender Bool
False (ASetter (Menu i) (Menu i) Int Int
-> (Int -> Int) -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter (Menu i) (Menu i) Int Int
forall c a. HasMenu c a => Lens' c Int
Menu.selected Int -> Int
add Menu i
m)
  where
    count :: Int
count =
      (Int -> Int) -> (Int -> Int -> Int) -> Maybe Int -> Int -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int -> Int
forall a. a -> a
id Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Maybe Int
maxItems ([FilteredMenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilteredMenuItem i]
filtered)
    add :: Int -> Int
add Int
current =
      if Int
count Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Int
0 else (Int
current Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
offset) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
count

menuToggle ::
  Monad m =>
  Menu i ->
  Prompt ->
  m (MenuConsumerAction m a, Menu i)
menuToggle :: Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuToggle m :: Menu i
m@(Menu [MenuItem i]
_ [FilteredMenuItem i]
_ Int
selected [Int]
marked MenuFilter
_ Maybe Int
_) Prompt
prompt =
  Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuRender Bool
True (Menu i -> m (MenuConsumerAction m a, Menu i))
-> ((MenuConsumerAction m Any, Menu i) -> Menu i)
-> (MenuConsumerAction m Any, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuConsumerAction m Any, Menu i) -> Menu i
forall a b. (a, b) -> b
snd ((MenuConsumerAction m Any, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> m (MenuConsumerAction m Any, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Int -> Menu i -> Prompt -> m (MenuConsumerAction m Any, Menu i)
forall (m :: * -> *) i a.
Monad m =>
Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle Int
1 Menu i
newMenu Prompt
prompt
  where
    newMenu :: Menu i
newMenu =
      ASetter (Menu i) (Menu i) [Int] [Int] -> [Int] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [Int] [Int]
forall c a. HasMenu c a => Lens' c [Int]
Menu.marked [Int]
newMarked Menu i
m
    newMarked :: [Int]
newMarked =
      if [Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
removed Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
marked then Int
selected Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
marked else [Int]
removed
    removed :: [Int]
removed =
      (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int
selected Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/=) [Int]
marked

menuToggleAll ::
  Monad m =>
  Menu i ->
  Prompt ->
  m (MenuConsumerAction m a, Menu i)
menuToggleAll :: Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuToggleAll m :: Menu i
m@(Menu [MenuItem i]
_ [FilteredMenuItem i]
filtered Int
_ [Int]
marked MenuFilter
_ Maybe Int
_) Prompt
_ =
  Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Bool -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuRender Bool
True Menu i
newMenu
  where
    newMenu :: Menu i
newMenu =
      ASetter (Menu i) (Menu i) [Int] [Int] -> [Int] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [Int] [Int]
forall c a. HasMenu c a => Lens' c [Int]
Menu.marked (Int -> [Int] -> [Int]
indexesComplement ([FilteredMenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FilteredMenuItem i]
filtered) [Int]
marked) Menu i
m

menuUpdatePrompt ::
  Applicative m =>
  Prompt ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
menuUpdatePrompt :: Prompt -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuUpdatePrompt Prompt
prompt =
  (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> (MenuConsumerAction m a, Menu i))
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Prompt -> MenuConsumerAction m a
forall (m :: * -> *) a. Prompt -> MenuConsumerAction m a
MenuConsumerAction.UpdatePrompt Prompt
prompt,)