module Libgit.FFI

import Prelude
import System.FFI

import Libgit.Types

-- FFI string builders

public export
libgit : String -> String
libgit fn = "C:" ++ fn ++ ",libgit2"

public export
libgitWrapper : String -> String
libgitWrapper fn = "C:" ++ fn ++ ",libgit_idris_wrapper"

-- Structs

export
CGitResult : Type
CGitResult = Struct "git_result" [
  ("obj", AnyPtr),
  ("result", Int)
]

export
%foreign "C:free,libc"
prim_free : AnyPtr -> PrimIO ()

%foreign (libgitWrapper "identity")
derefResult : Ptr CGitResult -> CGitResult

export
getGitResultPair : Ptr CGitResult -> IO (Int, AnyPtr)
getGitResultPair cgrPtr = do
  let cgr : CGitResult = derefResult cgrPtr
      err : Int = getField cgr "result"
      ptr : AnyPtr = getField cgr "obj"
  primIO (prim_free (prim__forgetPtr cgrPtr))
  pure (err, ptr)

export
getGitResult : Ptr CGitResult -> IO (GitResult AnyPtr)
getGitResult cgrPtr = do
  (err, ptr) <- getGitResultPair cgrPtr
  case err of
    0 => pure (Right ptr)
    _ => pure (Left err)

public export
CGitError : Type
CGitError = Struct "git_error" [
  ("message", Ptr String),
  ("klass", Int)
]

export
%foreign (libgitWrapper "identity")
derefGitError : Ptr CGitError -> CGitError

-- System info helpers
---- These should be generated by the build system until type providers exist

CUInt : Type
CUInt = Bits32

CSizeT : Type
CSizeT = Bits32

-- FFI functions

export
%foreign (libgitWrapper "make_string")
make_string : String -> Ptr String

export
%foreign (libgitWrapper "is_null")
is_null_string : Ptr String -> Int

export
%foreign (libgitWrapper "is_null")
is_null_ptr : AnyPtr -> Int

export
%foreign (libgitWrapper "get_string")
getString : Ptr String -> String

export
%foreign (libgitWrapper "null_string")
null_string : Ptr String

export
%foreign (libgitWrapper "null_string")
null_ptr : AnyPtr

export
%foreign (libgit "git_libgit2_init")
prim_libgit_init : PrimIO Int

export
%foreign (libgit "git_libgit2_shutdown")
prim_libgit_shutdown : PrimIO Int

export
%foreign (libgitWrapper "apply_clone_options")
prim_apply_clone_options : AnyPtr -> String -> Int -> PrimIO ()

export
%foreign (libgitWrapper "make_clone_options")
prim_init_clone_options : PrimIO AnyPtr

export
%foreign (libgitWrapper "git_clone_options_version")
git_clone_options_version : Int

export
%foreign (libgit "git_clone_init_options")
prim_git_clone_init_options : AnyPtr -> Int -> PrimIO Int

export
%foreign (libgitWrapper "git_clone_repository")
prim_git_clone_repository :  String -> String -> AnyPtr -> PrimIO (Ptr CGitResult)

export
%foreign (libgit "git_repository_free")
prim_git_repository_free : AnyPtr -> PrimIO ()

export
%foreign (libgitWrapper "git_open_repository")
prim_git_open_repository : String -> PrimIO (Ptr CGitResult)

export
%foreign (libgitWrapper "git_checkout_options_init")
git_checkout_options_init : Ptr CGitResult

export
%foreign (libgitWrapper "git_fetch_options_init")
git_fetch_options_init : Ptr CGitResult

export
%foreign (libgit "git_reset")
prim_git_reset : AnyPtr -> AnyPtr -> Int -> AnyPtr -> PrimIO Int

export
%foreign (libgitWrapper "git_oid_from_string")
git_oid_from_string : String -> Ptr CGitResult

export
%foreign (libgitWrapper "git_oid_to_string")
git_oid_to_string : AnyPtr -> String

export
%foreign (libgitWrapper "git_lookup_object")
git_lookup_object : AnyPtr -> AnyPtr -> Int -> Ptr CGitResult

export
%foreign (libgitWrapper "git_single_revparse")
prim_git_single_revparse : AnyPtr -> String -> PrimIO (Ptr CGitResult)

export
%foreign (libgit "git_object_free")
prim_git_object_free : AnyPtr -> PrimIO ()

export
%foreign (libgit "git_object_type")
git_object_type : AnyPtr -> Int

export
%foreign (libgitWrapper "git_lookup_remote")
git_lookup_remote : AnyPtr -> String -> Ptr CGitResult

export
%foreign (libgit "git_remote_free")
prim_git_remote_free : AnyPtr -> PrimIO ()

export
%foreign (libgit "git_remote_fetch")
prim_git_remote_fetch : AnyPtr -> AnyPtr -> AnyPtr -> Ptr String -> PrimIO Int

export
%foreign (libgit "giterr_last")
git_error_last : Ptr CGitError

export
liftPIO : (HasIO m) => PrimIO a -> m a
liftPIO action = liftIO (primIO action)

export
cBool : Bool -> Int
cBool True = 1
cBool False = 0
