{-# LANGUAGE OverloadedStrings #-}

-- | Module for updating environment variables. All functions take either 'HKLM' to modify the
--   variable for the machine, or 'HKCU' to modify for the user.
--
--   /Warning:/ If you are modifying PATH, make sure you use a special build of NSIS which can cope
--   with longer strings, or you will corrupt your users path.
module Development.NSIS.Plugins.EnvVarUpdate(
    getEnvVar, setEnvVar, deleteEnvVar,
    setEnvVarAppend, setEnvVarPrepend, setEnvVarRemove
    ) where

import Development.NSIS
import Development.NSIS.Plugins.WinMessages
import Control.Monad
import Data.String


resolve :: HKEY -> String
resolve h | h == HKLM || h == HKEY_LOCAL_MACHINE = "SYSTEM/CurrentControlSet/Control/Session Manager/Environment"
          | h == HKCU || h == HKEY_CURRENT_USER = "Environment"
          | otherwise = error $ "Development.NSIS.Plugins.EnvVarUpdate, must use either HKLM or HKCU, got: " ++ show h


-- | Given a string, and a ; separated variable, remove the string from it if it is present.
remove :: Exp String -> Exp String -> Exp String
remove x xs = share x $ \x -> share xs $ \xs -> do
    xs <- mutable_ xs
    xs @= strReplace (";" & x & ";") ";" xs
    while ((x & ";") `strIsPrefixOf` xs) $ xs @= strDrop (strLength x + 1) xs
    while ((";" & x) `strIsSuffixOf` xs) $ xs @= strTake (strLength xs - 1 - strLength x) xs
    iff_ (x %== xs) $ xs @= ""
    xs


-- | Set an environment variable by writing to the registry.
setEnvVar :: HKEY -> Exp String -> Exp String -> Action ()
setEnvVar h key val = do
    writeRegExpandStr h (fromString $ resolve h) key (strCheck val)
    void $ sendMessage [Timeout 5000] hwnd_BROADCAST wm_WININICHANGE (0 :: Exp Int) ("STR:Environment" :: Exp String)


-- | Read a variable from the registry. If you are not modifying the variable
--   you should use 'envVar' instead.
getEnvVar :: HKEY -> Exp String -> Exp String
getEnvVar h key = strCheck $ readRegStr h (fromString $ resolve h) key


-- | Delete the environment variable in the registry.
deleteEnvVar :: HKEY -> Exp String -> Action ()
deleteEnvVar h key = do
    deleteRegValue h (fromString $ resolve h) key
    void $ sendMessage [Timeout 5000] hwnd_BROADCAST wm_WININICHANGE (0 :: Exp Int) ("STR:Environment" :: Exp String)


setEnvVarAppend :: HKEY -> Exp String -> Exp String -> Action ()
setEnvVarAppend h key val = share val $ \val -> setEnvVar h key $ remove val (getEnvVar h key) & ";" & val

setEnvVarPrepend :: HKEY -> Exp String -> Exp String -> Action ()
setEnvVarPrepend h key val = share val $ \val -> setEnvVar h key $ val & ";" & remove val (getEnvVar h key)

setEnvVarRemove :: HKEY -> Exp String -> Exp String -> Action ()
setEnvVarRemove h key val = setEnvVar h key $ remove val $ getEnvVar h key