-- | Operations involving Offset and Range through an Engine
module Offset where
import Text.Regex.Posix 
import Data.List (find)
import Data.Maybe (fromJust)
import Control.Monad.State
import Editor
import Engine

-- | move the cursor in the engine
jumpE 		:: Ctx m  	
	=> Offset 		-- ^ the new position for the cursor
	-> Editor m Engine		-- ^ the modified engine under the Editor

jumpE Current 		= through  Just 
jumpE LastLine 		= through  Engine.last  
jumpE (Next n) 		= through  $ nextn n  
jumpE (Prev n) 		= through  $ prevn n 
jumpE (Absolute n) 	= through  $ jump n 
jumpE (ReNext s)  	= putlastre s >> (through . finder fwdcycle) s
jumpE LastReNext  	= gets lastre >>= through . finder fwdcycle 
jumpE (RePrev s)  	= putlastre s >> (through . finder bwdcycle) s
jumpE LastRePrev 	= gets lastre >>= through . finder bwdcycle 

                
finder f s = find  ((=~ s) . fromJust . line) . f

-- | From a range to the tuple (nelements,starting range element)
rangeResolve 	:: Ctx m  
	=> Range 			-- ^ the range to focus
	-> Editor m (Int,  Engine)	-- ^ the tuple (nelements,engine placed
					-- at first offset of range)
rangeResolve (Range o1 o2) 	= do 
	w1 <- jumpE o1 
	w2 <- jumpE o2 
	return (distance (pos w1) (pos w2) , w1)

-- | a complete backend + Editor action on an Offset
doOffset	:: Ctx m 	
	=> Offset 		-- ^ Offset for the action
	-> (a -> Editor m b) 	-- ^ the final action
	-> (Engine -> Maybe a) 	-- ^ the backend ation
	-> Editor m b		-- ^ ..
doOffset o ef mf 	= jumpE o >>= backend . mf >>= ef

-- | a backend action ending in a save state for the file
editOffset 	:: Ctx m 
	=> Offset 			-- ^ Offset for the backend action
	-> (Engine -> Maybe Engine) 	-- ^ the backend ation
	-> Editor m () 			-- ^ modified monad
editOffset o 		= doOffset o hputfile 

-- | a complete backend + Editor action on a Range
doRange		:: Ctx m
	=> Range			-- ^ the addressed range
	-> (a -> Editor m b)		-- ^ the closing Editor action
	-> (Int -> Engine -> Maybe a)	-- ^ the backend action 
	-> Editor m b	-- ^ ... 
doRange r ef mf 	= rangeResolve r >>= backend . uncurry mf >>= ef

editRange 	:: Ctx m
	=> Range				-- ^ the addressed range
	-> (Int -> Engine -> Maybe Engine)	-- ^ the backend action 
	-> Editor m ()				-- ^ modified monad
editRange r 		= doRange r hputfile