module Engine where
import Test.QuickCheck
import Control.Monad
import Data.Maybe
import Data.List
type Change a = a -> Maybe a
data Pos
= Line {
nth :: Int
}
| Begin
| End {
lns :: Int
}
deriving Show
distance (Line n) (Line m) = m n +1
distance Begin (Line m) = m
distance (Line n) (End m) = m n
distance Begin (End m) = m
distance _ _ = 0
data Engine
= Inside {
left :: [String],
cursor ::String ,
right :: [String]
}
| Corner
{
elems :: Either [String] [String]
}
deriving (Show , Eq)
empty :: Engine
empty = listIn []
listIn :: [String] -> Engine
listOut :: Engine -> Maybe [String]
linen :: Int -> Engine -> Maybe [String]
line :: Engine -> Maybe String
line w = head `fmap` linen 1 w
jump :: Int -> Change Engine
ins :: [String] -> Change Engine
add :: [String] -> Change Engine
del :: Change Engine
deln :: Int -> Change Engine
end :: Change Engine
start :: Change Engine
pos :: Engine -> Pos
next :: Change Engine
prev :: Change Engine
prevn :: Int -> Change Engine
prevn 0 w = Just w
prevn n w = prev w >>= prevn (n1)
nextn :: Int -> Change Engine
nextn 0 w = Just w
nextn n w = next w >>= nextn (n1)
rjump :: Int -> Change Engine
rjump n = iterateM n (if n > 0 then next else prev) where
iterateM n f w | n > 0 = f w >>= iterateM (n 1) f
| True = Just w
tillend :: Engine -> [Engine]
fwdcycle :: Engine -> [Engine]
fromstart :: Engine -> [Engine]
bwdcycle :: Engine -> [Engine]
last :: Change Engine
last t = end t >>= prev
first :: Change Engine
first t = start t >>= next
listIn xs = Corner (Right xs)
prev (Corner (Right _ )) = Nothing
prev (Corner (Left [] )) = error "empty Corner Left"
prev (Corner (Left (l:ls))) = Just $ Inside ls l []
prev (Inside [] x ls) = Just $ Corner (Right (x:ls))
prev (Inside (l:ls) x rs) = Just $ Inside ls l (x:rs)
next (Corner (Right [] )) = Nothing
next (Corner (Right (r:rs))) = Just $ Inside [] r rs
next (Corner (Left [] )) = error "empty Corner Left"
next (Corner (Left _ )) = Nothing
next (Inside ls x [] ) = Just $ Corner (Left (x:ls))
next (Inside ls x (r:rs)) = Just $ Inside (x:ls) r rs
end w@ (Corner (Left _)) = Just w
end w = next w >>= end
start w@ (Corner (Right _)) = Just w
start w = prev w >>= start
pos (Corner (Left ls)) = End (length ls + 1)
pos (Corner (Right _)) = Begin
pos (Inside ls _ _) = Line $ length ls + 1
del (Corner _) = Nothing
del (Inside [] _ [] ) = Just $ Corner (Right [])
del (Inside ls _ [] ) = Just $ Corner (Left ls)
del (Inside ls _ (r:rs)) = Just $ Inside ls r rs
deln n w | n == 0 = Just w
| True = del w >>= deln (n1)
add xs (Corner (Left _ )) = Nothing
add xs (Corner (Right rs)) = Just $ Corner $ Right (xs ++ rs)
add xs (Inside ls x rs) = Just $ Inside ls x (xs ++ rs)
ins xs w = prev w >>= add xs >>= next
jump n w = start w >>= rjump n
listOut w = start w >>= \(Corner (Right rs)) -> return rs
linen 0 _ = Just []
linen _ (Corner _) = Nothing
linen n w@ (Inside _ x _ ) = next w >>= linen (n 1) >>= Just . (x:)
tillend w = filter isInside (runner next w)
fromstart w = reverse $ filter isInside (runner prev w)
fwdcycle w = filter isInside $ runner next w ++ reverse (runner prev w) ++ [w]
bwdcycle w = filter isInside $ runner prev w ++ reverse (runner next w) ++ [w]
isInside :: Engine -> Bool
isInside (Inside _ _ _) = True
isInside _ = False
runner :: Change Engine -> Engine -> [Engine]
runner op w = maybe [] (\w -> (w : runner op w)) (op w)