module Yi.Keymap.Vim2.Ex.Commands.Global
    ( parse
    ) where

import Prelude ()
import Yi.Prelude

import Data.List (reverse, isInfixOf)
import qualified Text.ParserCombinators.Parsec as P

import Yi.Buffer
import Yi.Editor
import Yi.Keymap
import Yi.Keymap.Vim2.Ex.Types
import qualified Yi.Keymap.Vim2.Ex.Commands.Common as Common
import qualified Yi.Keymap.Vim2.Ex.Commands.Delete as Delete
import qualified Yi.Keymap.Vim2.Ex.Commands.Substitute as Substitute

parse :: String -> Maybe ExCommand
parse = Common.parse $ do
    discard $ P.try (P.string "global/") <|> P.string "g/"
    predicate <- P.many (P.noneOf "/")
    discard $ P.char '/'
    cmdString <- P.many P.anyChar
    cmd <- case stringToExCommand allowedCmds cmdString of
            Just c -> return c
            _ -> fail "Unexpected command argument for global command."
    return $! global predicate cmd

global :: String -> ExCommand -> ExCommand
global p c = Common.pureExCommand {
    cmdShow = concat ["g/", p, "/", show c]
  , cmdAction = EditorA $ do
        mark <- withBuffer0 setMarkHereB
        lineCount <- withBuffer0 lineCountB
        forM_ (reverse [1..lineCount]) $ \l -> do
            ln <- withBuffer0 $ gotoLn l >> readLnB
            when (p `isInfixOf` ln) $
                case cmdAction c of
                    BufferA action -> withBuffer0 $ discard action
                    EditorA action -> discard action
                    _ -> error "Impure command as an argument to global."
        withBuffer0 $ do
            getMarkPointB mark >>= moveTo
            deleteMarkB mark
  }

allowedCmds :: [String -> Maybe ExCommand]
allowedCmds = [Delete.parse, Substitute.parse]