module Data.List.PointedList.Circular
  ( -- Re-export many of the regular PointedList features
  module Data.List.PointedList

  -- And, of course, export the alternatives here
  , next
  , previous
  , delete
  , deleteLeft
  , deleteRight
  , moveN
  ) where

import Data.List.PointedList
  ( PointedList(..)
  , focus
  , singleton
  , fromList
  , fromListEnd
  , replace
  , insert
  , insertLeft
  , insertRight
  , deleteOthers
  , length
  , positions
  , contextMap
  , withFocus
  , find
  , index
  )
import qualified Data.List.PointedList as PL

-- | Move the focus to the next element in the list. If the last element is
--   currently focused, loop to the first element.
next :: PointedList a -> PointedList a
next :: PointedList a -> PointedList a
next pl :: PointedList a
pl@(PointedList [] b :: a
b []) = PointedList a
pl
next    (PointedList a :: [a]
a  b :: a
b []) = let (x :: a
x:xs :: [a]
xs) = [a] -> [a]
forall a. [a] -> [a]
reverse [a]
a in
                                  [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList [] a
x ([a]
xs [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
b])
next pl :: PointedList a
pl = PointedList a -> PointedList a
forall a. PointedList a -> PointedList a
PL.tryNext PointedList a
pl 

-- | Move the focus to the previous element in the list. If the first element is
--   currently focused, loop to the last element.
previous :: PointedList a -> PointedList a
previous :: PointedList a -> PointedList a
previous pl :: PointedList a
pl@(PointedList [] b :: a
b []) = PointedList a
pl
previous    (PointedList [] b :: a
b c :: [a]
c ) = let (x :: a
x:xs :: [a]
xs) = [a] -> [a]
forall a. [a] -> [a]
reverse [a]
c in
                                      [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList ([a]
xs [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
b]) a
x []
previous pl :: PointedList a
pl = PointedList a -> PointedList a
forall a. PointedList a -> PointedList a
PL.tryPrevious PointedList a
pl

-- | An alias of 'deleteRight'.
delete :: PointedList a -> Maybe (PointedList a)
delete :: PointedList a -> Maybe (PointedList a)
delete = PointedList a -> Maybe (PointedList a)
forall a. PointedList a -> Maybe (PointedList a)
deleteRight

-- | Possibly delete the element at the focus, then move the element on the
--   left to the focus. If no element is on the left, focus on the element to
--   the right. If the deletion will cause the list to be empty, return
--   @Nothing@.
deleteLeft :: PointedList a -> Maybe (PointedList a)
deleteLeft :: PointedList a -> Maybe (PointedList a)
deleteLeft (PointedList []     _ []) = Maybe (PointedList a)
forall a. Maybe a
Nothing
deleteLeft (PointedList (l :: a
l:ls :: [a]
ls) _ rs :: [a]
rs) = PointedList a -> Maybe (PointedList a)
forall a. a -> Maybe a
Just (PointedList a -> Maybe (PointedList a))
-> PointedList a -> Maybe (PointedList a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList [a]
ls a
l [a]
rs
deleteLeft (PointedList []     _ rs :: [a]
rs) = let (x :: a
x:xs :: [a]
xs) = [a] -> [a]
forall a. [a] -> [a]
reverse [a]
rs in
                                         PointedList a -> Maybe (PointedList a)
forall a. a -> Maybe a
Just (PointedList a -> Maybe (PointedList a))
-> PointedList a -> Maybe (PointedList a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList [a]
xs a
x []

-- | Possibly delete the element at the focus, then move the element on the
--   right to the focus. If no element is on the right, focus on the element to
--   the left. If the deletion will cause the list to be empty, return
--   @Nothing@.
deleteRight :: PointedList a -> Maybe (PointedList a)
deleteRight :: PointedList a -> Maybe (PointedList a)
deleteRight (PointedList [] _ []    ) = Maybe (PointedList a)
forall a. Maybe a
Nothing
deleteRight (PointedList ls :: [a]
ls _ (r :: a
r:rs :: [a]
rs)) = PointedList a -> Maybe (PointedList a)
forall a. a -> Maybe a
Just (PointedList a -> Maybe (PointedList a))
-> PointedList a -> Maybe (PointedList a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList [a]
ls a
r [a]
rs
deleteRight (PointedList ls :: [a]
ls _ []    ) = let (x :: a
x:xs :: [a]
xs) = [a] -> [a]
forall a. [a] -> [a]
reverse [a]
ls in
                                            PointedList a -> Maybe (PointedList a)
forall a. a -> Maybe a
Just (PointedList a -> Maybe (PointedList a))
-> PointedList a -> Maybe (PointedList a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> PointedList a
forall a. [a] -> a -> [a] -> PointedList a
PointedList [] a
x [a]
xs

-- | Move
moveN :: Int -> PointedList a -> PointedList a
moveN :: Int -> PointedList a -> PointedList a
moveN 0 pl :: PointedList a
pl = PointedList a
pl
moveN n :: Int
n pl :: PointedList a
pl | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0     = Int -> PointedList a -> PointedList a
forall a. Int -> PointedList a -> PointedList a
moveN (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-1) (PointedList a -> PointedList a) -> PointedList a -> PointedList a
forall a b. (a -> b) -> a -> b
$ PointedList a -> PointedList a
forall a. PointedList a -> PointedList a
next PointedList a
pl
           | Bool
otherwise = Int -> PointedList a -> PointedList a
forall a. Int -> PointedList a -> PointedList a
moveN (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (PointedList a -> PointedList a) -> PointedList a -> PointedList a
forall a b. (a -> b) -> a -> b
$ PointedList a -> PointedList a
forall a. PointedList a -> PointedList a
previous PointedList a
pl