module Darcs.UI.Commands.Convert.Util
    ( Marks
    , emptyMarks
    , addMark
    , getMark
    , lastMark
    , readMarks
    , writeMarks
    -- misc
    , patchHash
    , updatePending
    ) where

import Darcs.Prelude

import Darcs.Util.Exception ( catchall )

import qualified Data.ByteString.Char8 as BC
import qualified Data.IntMap as M

import System.Directory ( removeFile )

import Darcs.Patch.Info ( makePatchname )
import Darcs.Patch.PatchInfoAnd ( PatchInfoAnd, info )

import Darcs.Repository.Flags ( UpdatePending(..) )
import Darcs.UI.Options ( (?) )
import qualified Darcs.UI.Options.All as O
import Darcs.UI.Flags ( DarcsFlag )

-- marks support

type Marks = M.IntMap BC.ByteString

emptyMarks :: Marks
emptyMarks = M.empty

lastMark :: Marks -> Int
lastMark m = if M.null m then 0 else fst $ M.findMax m

getMark :: Marks -> Int -> Maybe BC.ByteString
getMark marks key = M.lookup key marks

addMark :: Marks -> Int -> BC.ByteString -> Marks
addMark marks key value = M.insert key value marks

readMarks :: FilePath -> IO Marks
readMarks p = do lines' <- BC.split '\n' `fmap` BC.readFile p
                 return $ foldl merge M.empty lines'
               `catchall` return emptyMarks
  where merge set line = case BC.split ':' line of
          [i, hash] -> M.insert (read $ BC.unpack i) (BC.dropWhile (== ' ') hash) set
          _ -> set -- ignore, although it is maybe not such a great idea...

writeMarks :: FilePath -> Marks -> IO ()
writeMarks fp m = do removeFile fp `catchall` return () -- unlink
                     BC.writeFile fp marks
  where marks = BC.concat $ map format $ M.assocs m
        format (k, s) = BC.concat [BC.pack $ show k, BC.pack ": ", s, BC.pack "\n"]

-- misc shared functions

patchHash :: PatchInfoAnd rt p cX cY -> BC.ByteString
patchHash p = BC.pack $ show $ makePatchname (info p)

updatePending :: [DarcsFlag] -> UpdatePending
updatePending opts =
  case O.withWorkingDir ? opts of
    O.WithWorkingDir -> YesUpdatePending
    O.NoWorkingDir -> NoUpdatePending