module System.Directory

import public System.File
import System.FFI

%default total

public export
DirPtr : Type
DirPtr = AnyPtr

support : String -> String
support fn = "C:" ++ fn ++ ", libidris2_support, idris_directory.h"

directoriesClass : String
directoriesClass = "io/github/mmhelloworld/idrisjvm/runtime/Directories"

%foreign "C:idris2_fileErrno, libidris2_support, idris_file.h"
         "node:support:fileErrno,support_system_file"
         jvm' runtimeClass "getErrorNumber" "java/lang/Object" "int"
prim__fileErrno : PrimIO Int

returnError : HasIO io => io (Either FileError a)
returnError
    = do err <- primIO prim__fileErrno
         pure $ Left $
           case err of
              0 => FileReadError
              1 => FileWriteError
              2 => FileNotFound
              3 => PermissionDenied
              4 => FileExists
              _ => GenericFileError (err-5)

ok : HasIO io => a -> io (Either FileError a)
ok x = pure (Right x)

%foreign support "idris2_currentDirectory"
         "node:lambda:()=>process.cwd()"
         jvm directoriesClass "getWorkingDirectory"
prim__currentDir : PrimIO (Ptr String)

%foreign support "idris2_changeDir"
         "node:support:changeDir,support_system_directory"
         jvm directoriesClass "changeDirectory"
prim__changeDir : String -> PrimIO Int

%foreign support "idris2_createDir"
         "node:support:createDir,support_system_directory"
         jvm directoriesClass "createDirectory"
prim__createDir : String -> PrimIO Int

%foreign support "idris2_openDir"
         jvm directoriesClass "openDirectory"
prim__openDir : String -> PrimIO DirPtr

%foreign support "idris2_closeDir"
         jvm directoriesClass "closeDirectory"
prim__closeDir : DirPtr -> PrimIO ()

%foreign support "idris2_removeDir"
         jvm directoriesClass "delete"
prim__removeDir : String -> PrimIO ()

%foreign support "idris2_nextDirEntry"
         jvm directoriesClass "getNextDirectoryEntry"
prim__dirEntry : DirPtr -> PrimIO (Ptr String)

export
data Directory : Type where
     MkDir : DirPtr -> Directory

export
createDir : HasIO io => String -> io (Either FileError ())
createDir dir
    = do res <- primIO (prim__createDir dir)
         if res == 0
            then ok ()
            else returnError

export
changeDir : HasIO io => String -> io Bool
changeDir dir
    = do ok <- primIO (prim__changeDir dir)
         pure (ok == 0)

export
currentDir : HasIO io => io (Maybe String)
currentDir
    = do res <- primIO prim__currentDir
         if prim__nullPtr res /= 0
            then pure Nothing
            else pure (Just (prim__getString res))

export
openDir : HasIO io => String -> io (Either FileError Directory)
openDir d
    = do res <- primIO (prim__openDir d)
         if prim__nullAnyPtr res /= 0
            then returnError
            else ok (MkDir res)

export
closeDir : HasIO io => Directory -> io ()
closeDir (MkDir d) = primIO (prim__closeDir d)

export
removeDir : HasIO io => String -> io ()
removeDir dirName = primIO (prim__removeDir dirName)

export
dirEntry : HasIO io => Directory -> io (Either FileError String)
dirEntry (MkDir d)
    = do res <- primIO (prim__dirEntry d)
         if prim__nullPtr res /= 0
            then returnError
            else ok (prim__getString res)
