```{-# LINE 1 "Optimize/ASA.hsc" #-}
{-# OPTIONS -ffi -fglasgow-exts #-}
{-# LINE 2 "Optimize/ASA.hsc" #-}
-- | interface to the Adaptive Simulated Annealing algorithm.

module Optimize.ASA where

{-# LINE 7 "Optimize/ASA.hsc" #-}

import Optimize.Parameter
import Foreign.C.Types
import Foreign.Storable
import Foreign.Ptr
import Foreign.Marshal.Array
import Foreign.Marshal.Alloc
import Random
import Data.Array.Unboxed
import Data.Int

newtype UserOptions = UserOptions (Ptr UserOptions)
type Doubles = UArray Int Double

data ExitCode =  NormalExit | PTempTooSmall | CTempTooSmall | CostRepeating | TooManyInvalidStates | ImmediateExit | InvalidUserInput | InvalidCostFunction | InvalidCostFunctionDeriv

data Results x = Results {
optimalValue :: Double,
optimalParam :: x,
exitCode :: ExitCode
}

type CostFunction =  Ptr Double -> Ptr Int -> IO Double

foreign import ccall "wrapper" mkCostFunction :: CostFunction -> IO (FunPtr CostFunction)
foreign import ccall "asa_usr.h asa_main" asa_main :: FunPtr CostFunction -> CInt -> Ptr Double -> Ptr Double -> Ptr CInt -> Ptr Double -> Ptr Double -> Ptr CInt -> CInt -> IO CInt

asa :: UserOptions     -- Options
-> (Doubles -> IO (Maybe Double)) -- cost function
-> Int64           -- random number seed
-> Maybe Doubles   -- starting position
-> Doubles         -- upper bounds
-> Doubles         -- lower bounds
-> UArray Int Bool -- parameters are integral
-> IO (ExitCode,Doubles)      -- final answers
asa = undefined

toBasicCostFunction :: Parameter z x => z -> (x -> Double) -> CostFunction
toBasicCostFunction z fn = f where
thePeek = peekParam z
f pd pf = do
poke pf 1
x <- thePeek pd
let v = fn x
--putStrLn \$ ">> Haskell Function Called: " ++ show v
return \$  v

minimize :: Parameter z x => z -> (x -> Double) -> IO x
minimize z (fn :: x -> Double ) = do
cf <- mkCostFunction (toBasicCostFunction z fn)
let n = numParams (undefined :: x) z
let ps = paramInfo (undefined :: x) z []
withArray (map limitLow ps) \$ \lower_bounds -> do
withArray (map limitHigh ps) \$ \upper_bounds -> do
withArray (map (\x -> if isIntegral x then (1) else (-1)) ps) \$ \real_int -> do
{-# LINE 70 "Optimize/ASA.hsc" #-}
alloca \$ \dummy_cost_val -> do
allocaArray n \$ \ret -> do
alloca \$ \exit_code -> do
r <- randomIO
asa_main cf (fromIntegral n) upper_bounds lower_bounds real_int dummy_cost_val ret exit_code (fromIntegral (r :: Int))
--code <- peek exit_code
--print (toEnum (fromIntegral code) :: ExitCode)
peekParam z ret

```