module JDBC where
import System.Directory
import JVMBridge
import RawVM

test :: IO ()
test =
  let lib = "drivers" in
  getDirectoryContents lib >>= \libs ->
  let cp = lib : [lib ++ "/" ++ fp | fp <- libs, (head fp /= '.')] in
  createJavaVM cp >>= \vm ->
  case (3 :: Int) of {1 -> (
  -- Works as expected, but isn't what we need:
  runWithVM vm (runReport $
    jdbcDriverConnection "oracle.jdbc.OracleDriver"
      "jdbc:oracle:thin:@***:1521:ORCL"
      "***" "***" >>
    jdbcDriverConnection "com.mysql.jdbc.Driver"
      "jdbc:mysql://***/***?autoReconnect=true&dumpQueriesOnException=true"
      "***" "***")
  ); 2 -> (
  -- Doesn't work: "Java throwable: java.sql.SQLException: No suitable driver".
  -- "The main thread cannot detach itself from the VM. Instead, it must call DestroyJavaVM() to unload the entire VM.
  --  The VM waits until the main thread is the only user thread before it actually unloads."
  -- http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/invocation.html
  runWithVM vm (runReport $ jdbcDriverConnection "oracle.jdbc.OracleDriver"
    "jdbc:oracle:thin:@***:1521:ORCL"
    "***" "***") >>
  runWithVM vm (runReport $ jdbcDriverConnection "com.mysql.jdbc.Driver"
    "jdbc:mysql://***/***?autoReconnect=true&dumpQueriesOnException=true"
    "***" "***")
  ); 3 -> (
  -- Works as expected, and within the IO monad instead of the JVM monad.
  rawAttachCurrentThread vm >>= \env ->
  (let ?jvmenv = env in runWithVMAndEnv vm (runReport $ jdbcDriverConnection "oracle.jdbc.OracleDriver"
    "jdbc:oracle:thin:@***:1521:ORCL"
    "***" "***")) >>
  (let ?jvmenv = env in runWithVMAndEnv vm (runReport $ jdbcDriverConnection "com.mysql.jdbc.Driver"
    "jdbc:mysql://***/***?autoReconnect=true&dumpQueriesOnException=true"
    "***" "***")) >>
  rawDetachCurrentThread vm
  ); _ -> return ()}

-- Standard JVM section, generated by MakeJVMModule.
data Preload = MkPreload { cPreload_dummy::() }
type JVM = JVMUser Preload
instance IsJVMLoadable JVMStandard Preload where
  jvmLoad = return (MkPreload ())

dotToSlash :: Jchar -> Jchar
dotToSlash 46 = 47
dotToSlash c = c

jdbcDriverConnection driver url name pwd =
  (findClassByName (fmap dotToSlash $ toJavaString driver) :: JVM JClass) >>= \(driverClass :: JClass) ->

  findClass (Type :: Type Jjava_sql_DriverManager) >>= \driverManagerClass ->
  getStaticMethod driverManagerClass (toJavaString "getConnection") >>=
  \(getConnection :: (JString,JString,JString) -> JVM Jjava_sql_Connection) ->

  findClass (Type :: Type JString) >>= \classString ->
  getMakeNewObject classString >>= \(newString :: ([Jchar]) -> JVM JString) ->
  getMethod classString (toJavaString "toCharArray") >>= \(toCharArray :: JString -> () -> JVM [Jchar]) ->

  newString (toJavaString url) >>= \urlString ->
  newString (toJavaString name) >>= \nameString ->
  newString (toJavaString pwd) >>= \pwdString ->

  getConnection (urlString, nameString, pwdString) >>= \connection ->
  callIO (putStrLn "Connected!") >>

  findClass (Type :: Type Jjava_sql_Connection) >>= \connectionIf ->
  getMethod connectionIf (toJavaString "getMetaData") >>=
  \(getMetaData :: Jjava_sql_Connection -> () -> JVM Jjava_sql_DatabaseMetaData) ->

  getMetaData connection () >>= \metaData ->

  findClass (Type :: Type Jjava_sql_DatabaseMetaData) >>= \databaseMetaDataIf ->
  getMethod databaseMetaDataIf (toJavaString "getTables") >>=
  \(getTables :: Jjava_sql_DatabaseMetaData -> (JString,JString,JString,[JString]) -> JVM Jjava_sql_ResultSet) ->

  findClass (Type :: Type Jjava_sql_ResultSet) >>= \resultSetIf ->
  getMethod resultSetIf (toJavaString "next") >>= \(rsNext :: Jjava_sql_ResultSet -> () -> JVM Bool) ->
  getMethod resultSetIf (toJavaString "getString") >>= \(rsString :: Jjava_sql_ResultSet -> (Jint) -> JVM JString) ->
  getMethod resultSetIf (toJavaString "getInt") >>= \(rsInt :: Jjava_sql_ResultSet -> (Jint) -> JVM Jint) ->

  getNothing >>= \(nullS :: JString) ->
  getNothing >>= \(nullL :: [JString]) ->
  newString (toJavaString "") >>= \tableNamePattern ->
  getTables metaData (nullS, nullS, tableNamePattern, nullL) >>= \tables ->

  while (
    rsNext tables () >>= \next -> if next then
      rsString tables 3 >>= \sCol1 ->
      toCharArray sCol1 () >>= \col1 ->
      callIO (putStrLn $ "next row: " ++ (showJavaString col1)) >>
      return True
    else return False
  ) >>
  return ()