-- GENERATED by C->Haskell Compiler, version 0.17.2 Crystal Seed, 24 Jan 2009 (Haskell)
-- Edit the ORIGNAL .chs file instead!


{-# LINE 1 "./Graphics/Wayland/Scanner.chs" #-}
{-# LANGUAGE TemplateHaskell #-}

module Graphics.Wayland.Scanner (
  generateTypes, generateEnums, generateMethods, generateListeners,
  generateRegistryBind,

  generateRegistryBindInternal,
  generateRegistryBindExternal,

  generateClientInternalListeners,
  generateServerInternalListeners,

  generateClientExternalListeners,
  generateServerExternalListeners,

  generateClientInternalMethods,
  generateServerInternalMethods,

  generateClientExternalMethods,
  generateServerExternalMethods,

  module Graphics.Wayland.Scanner.Types,
  module Graphics.Wayland.Scanner.Protocol,

  CInterface(..)

  ) where

import Data.Functor ((<$>))
import Data.Either (lefts, rights)
import Data.Maybe (fromJust)
import Data.List (findIndex)
import Control.Monad (liftM)
import Foreign
import Foreign.C.Types
import Foreign.C.String (withCString)
import Language.Haskell.TH
import Language.Haskell.TH.Syntax (VarStrictType)

import Graphics.Wayland
import Graphics.Wayland.Scanner.Marshaller
import Graphics.Wayland.Scanner.Names
import Graphics.Wayland.Scanner.Protocol
import Graphics.Wayland.Scanner.Types
import Graphics.Wayland.Internal.Util hiding (Client)
import Graphics.Wayland.Internal.Util as Util (Client)


-- Dear future maintainer,
-- I'm sorry.




generateTypes :: ProtocolSpec -> Q [Dec]
generateTypes ps = liftM concat $ sequence $ map generateInterface (protocolInterfaces ps) where
  generateInterface :: Interface -> Q [Dec]
  generateInterface iface = do
    let iname = interfaceName iface
        pname = protocolName ps
        qname = interfaceTypeName pname iname
    constructorType <- [t|$(conT ''Ptr) $(conT qname)|]
    typeDec <- newtypeD (return []) qname [] (normalC qname [return (NotStrict, constructorType)]) [mkName "Show", mkName "Eq"]

    -- We will later need a pointer to the wl_interface structs, for passing to wl_proxy_marshal_constructor and wl_resource_create.
    -- Now, a pretty solution would construct its own wl_interface struct here.
    -- But that's way too much work for me. We just bind to the one generated by the C scanner.
    cInterfaceDec <- forImpD cCall unsafe ("&"++iname ++ "_interface") (interfaceCInterfaceName pname iname ) [t| (CInterface)|] -- pointer is fixed
    return $ typeDec : cInterfaceDec : []

generateRegistryBind :: ProtocolSpec -> Q [Either Dec Dec]
generateRegistryBind ps = do
  let messageCreatesIface child msg = any (\ argument ->
        case argument of
          (_, NewIdArg _ x, _) -> x == interfaceName child
          _                                        -> False)
        (messageArguments msg)
      interfaceCreatesIface child parent = any (messageCreatesIface child) (interfaceRequests parent)
      protocolCreatesIface child = any (interfaceCreatesIface child) (protocolInterfaces ps)
      globalInterfaces = filter (not.protocolCreatesIface) $ filter (\iface -> interfaceName iface /= "wl_display") (protocolInterfaces ps)

  -- static inline void * wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
  -- id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_registry, WL_REGISTRY_BIND, interface, name, interface->name, version, NULL);
  -- struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, ...)
  liftM concat $ sequence $ map registryBindInterface globalInterfaces
    where
      registryBindInterface :: Interface -> Q [Either Dec Dec]
      registryBindInterface iface = do
        let iname = interfaceName iface
            pname = protocolName ps
            internalCName = mkName $ "wl_registry_" ++ iname ++ "_c_bind"
            exposeName = registryBindName pname iname

        fore <- forImpD cCall unsafe "wl_proxy_marshal_constructor" internalCName [t|$(conT $ mkName "Registry") -> (CUInt) -> CInterface -> CUInt -> Ptr CChar -> CUInt -> Ptr () -> IO $(conT $ interfaceTypeName pname iname) |]
        exposureDec <- [d|$(varP exposeName) = \ reg name strname version -> withCString strname $ \cstr -> $(varE internalCName) reg 0 $(varE $ interfaceCInterfaceName pname iname) (fromIntegral (name::Word)) cstr (fromIntegral (version::Word)) nullPtr |]
        return $ Left fore : map Right exposureDec

generateEnums :: ProtocolSpec -> [Dec]
generateEnums ps = concat $ map eachGenerateEnums (protocolInterfaces ps) where
  eachGenerateEnums :: Interface -> [Dec]
  eachGenerateEnums iface = concat $ map generateEnum $ interfaceEnums iface where
    generateEnum :: WLEnum -> [Dec]
    generateEnum wlenum =
      let qname = enumTypeName (protocolName ps) (interfaceName iface) (enumName wlenum)
      in
        NewtypeD [] qname [] (NormalC qname [(NotStrict, (ConT ''Int))]) [mkName "Show", mkName "Eq"]
        :
        map (\(entry, val) -> (ValD (VarP $ enumEntryHaskName (protocolName ps) (interfaceName iface) (enumName wlenum) entry) (NormalB $ (ConE qname) `AppE` (LitE $ IntegerL $ toInteger val)) [])) (enumEntries wlenum)

-- | generate FFI for a certain side of the API
--
--   Either Dec Dec explained: Left dec for internal declarations, Right dec for external declarations (ie. those that should be exposed to the user)
generateMethods :: ProtocolSpec -> ServerClient -> Q [Either Dec Dec]
generateMethods ps sc = liftM concat $ sequence $ map generateInterface $ filter (\iface -> if sc == Server then interfaceName iface /= "wl_display" else True) $ protocolInterfaces ps where
  generateInterface :: Interface -> Q [Either Dec Dec]
  generateInterface iface = do
    -- bind object destroyers
    let destroyName = mkName $ interfaceName iface ++ "_destructor"
    foreignDestructor <- forImpD cCall unsafe "wl_proxy_destroy" destroyName [t|$(conT $ interfaceTypeName (protocolName ps) (interfaceName iface)) -> IO ()|]


    -- Okay, we have to figure out some stuff. There is a tree of possibilities:
    -- - Server
    --   => this is actually an easy case. every message is just some call to wl_resource_post_event
    -- - Client
    -- - - if a message has more than one new_id argument, skip (or undefined for safety?)
    -- - - if a message has a single untyped new_id argument (ie now interface attribute in the XML), then there is some complicated C implementation we won't be copying, skip
    -- - - if a message has a single typed new_id argument, then this is the return value of wl_proxy_marshal_constructor
    --     => pass a bunch of constants in the initial arguments. pass NULL in its argument position
    -- - - if a message has no new_id arguments, we are calling wl_proxy_marshal
    --   => for each argument EXCEPT new_id's(where we would pass NULL as discussed), pass that argument
    -- Note that wl_resource_post_event, wl_proxy_marshal and wl_proxy_marshal_constructor all have the message index in the SECOND position: the object corresponding to the message is the first! So the important thing to remember is that our pretty Haskell function representations have some arguments inserted in between.
    --
    -- Further, in the Client case, we have to make a destructor. Some messages can have type="destructor" in the XML protocol files.
    -- - there is no message typed destructor with name "destroy"
    -- - - if the interface is wl_display, don't do anything
    -- - - if the interface is NOT wl_display
    --     => generate a new function "destroy", a synonnym for wl_proxy_destroy
    -- - otherwise, for each message typed destructor (possibly including "destroy")
    --   => call wl_proxy_marshal as normal, and *also* wl_proxy_destroy on this proxy (sole argument)
    -- - the case of having a "destroy", but no destructor, is illegal: iow, if you have a "destroy", then you must also have a destructor request.
    --   the C scanner allows you to have a non-destructor "destroy", but I doubt that's the intention, so I'll make that undefined.
    -- "dirty" name of internal raw binding to C function

    let needsDefaultDestructor = ((sc == Client) && (not $ any messageIsDestructor $ interfaceRequests iface) && (interfaceName iface /= "wl_display"))
    defaultDestructor <- [d|$(varP $ requestHaskName (protocolName ps) (interfaceName iface) "destroy") = \ proxy -> $(varE destroyName) proxy|]

    let
     generateMessage :: Int -> Message -> Q [Either Dec Dec]
     generateMessage idx msg = -- list idx used for wl_proxy_marshal arguments
       let pname = protocolName ps
           iname = interfaceName iface
           mname = messageName msg

           hname = case sc of
                     Server -> eventHaskName pname iname mname
                     Client -> requestHaskName pname iname mname
           internalCName = case sc of
                             Server -> mkName $ "wl_rpe_" ++ interfaceName iface ++ "_" ++ messageName msg
                             Client -> mkName $ "wl_pm_" ++ interfaceName iface ++ "_" ++ messageName msg

       in case sc of
            Server -> do
              -- void wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...);
              cdec <- forImpD cCall unsafe "wl_resource_post_event" internalCName [t|$(conT $ interfaceTypeName (protocolName ps) (interfaceName iface)) -> (CUInt) -> $(genMessageCType Nothing (messageArguments msg)) |]
              resourceName <- newName "resourceInternalName___"
              let messageIndexApplied = applyAtPosition (varE internalCName) (litE $ IntegerL $ fromIntegral idx) 1
                  resourceApplied = [e|$messageIndexApplied $(varE resourceName)|]
                  (pats,fun) = argTypeMarshaller (messageArguments msg) resourceApplied
              declist <- [d|$(varP hname) = $(LamE (VarP resourceName : pats) <$> fun)|]
              return (Left cdec:map Right declist)
            Client -> do
              let numNewIds = sum $ map (boolToInt . isNewId) $ messageArguments msg
                  argsWithoutNewId = filter (\arg -> not $ isNewId arg) (messageArguments msg)
                  returnArgument = head $ filter (\arg -> isNewId arg) (messageArguments msg)
                  returnName = let (_, NewIdArg _ theName, _) = returnArgument
                               in theName
                  returnType = [t|IO $(argTypeToCType returnArgument)|]
              cdec <- case numNewIds of
                        -- void wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
                        0 -> forImpD cCall unsafe "wl_proxy_marshal" internalCName [t|$(conT $ interfaceTypeName (protocolName ps) (interfaceName iface)) -> (CUInt) -> $(genMessageCType Nothing (messageArguments msg)) |]
                        -- struct wl_proxy * wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, ...)
                        1 -> forImpD cCall unsafe "wl_proxy_marshal_constructor" internalCName [t|$(conT $ interfaceTypeName (protocolName ps) (interfaceName iface)) -> (CUInt) -> CInterface -> $(genMessageCType (Just returnType) (messageArguments msg)) |]


              proxyName <- newName "proxyInternalName___"
              let messageIndexApplied = applyAtPosition (varE internalCName) (litE $ IntegerL $ fromIntegral idx) 1
                  constructorApplied = case numNewIds of
                                         0 -> messageIndexApplied
                                         1 -> applyAtPosition messageIndexApplied (varE $ interfaceCInterfaceName pname (returnName)) 1
                  proxyApplied = [e|$constructorApplied $(varE proxyName)|]
                  makeArgumentNullPtr =
                      let argIdx = fromJust $ findIndex isNewId (messageArguments msg)
                          arg' = (messageArguments msg) !! argIdx
                          msgName = let (_,NewIdArg itsname _,_) = arg'
                                    in itsname
                      in [e|$(conE msgName) nullPtr|]
                  newIdNullInserted = case numNewIds of
                                        0 -> proxyApplied
                                        1 -> applyAtPosition proxyApplied makeArgumentNullPtr (fromJust $ findIndex isNewId (messageArguments msg))
                  finalCall = newIdNullInserted
                  (pats, fun) = argTypeMarshaller (argsWithoutNewId) finalCall
              declist <- [d|$(varP hname) = $(LamE (VarP proxyName : pats) <$> [e|do
                             -- Let's start by either calling wl_proxy_marshal or wl_proxy_marshal_constructor
                             retval <- $fun

                             -- possibly do some destruction here?
                             $(case messageIsDestructor msg of
                                 False -> [e|return retval|] -- do nothing (will hopefully get optimized away)
                                 True -> [e|$(varE destroyName) $(varE proxyName) |]
                                 )

                             return retval
                             |])|]

              return (Left cdec : map Right declist)



    -- bind individual messages
    theMessages <- liftM concat $ sequence $ zipWith generateMessage [0..] $
        case sc of
                    Server -> interfaceEvents iface
                    Client -> interfaceRequests iface

    return $ Left foreignDestructor : theMessages ++ if needsDefaultDestructor then map Right defaultDestructor else []


applyAtPosition :: ExpQ -> ExpQ -> Int -> ExpQ
applyAtPosition fun arg pos = do
  vars <- sequence $ map (\ _ -> newName "somesecretnameyoushouldntmesswith___") [0..(pos-1)]
  lamE (map varP vars) $
    appsE $ fun : (map varE vars) ++ [arg]

preComposeAt :: ExpQ -> ExpQ -> Int -> Int -> ExpQ
preComposeAt fun arg pos numArgs
  | pos > numArgs  = error "programming error"
preComposeAt fun arg pos numArgs = do
  vars <- sequence $ map (\ _ -> newName "yetanothernewvariablepleasedonttouchme___") [0..numArgs]
  lamE (map varP vars) $
    [e|do
      preCompVal <- $arg $(varE $ vars !! pos)
      $(appsE $ fun : (map varE $ take pos vars) ++ varE 'preCompVal : (map varE $ drop (pos+1) vars))
    |]

generateListeners :: ProtocolSpec -> ServerClient -> Q [Either Dec Dec]
generateListeners sp sc = do
  let pname = protocolName sp

  interfaces <- liftM concat $ sequence $ map (\iface -> generateListener sp iface sc) $
    filter (\iface -> 0 < (length $ case sc of
                                      Server -> interfaceRequests iface
                                      Client -> interfaceEvents iface)) $ protocolInterfaces sp
  resourceCreators <-
    case sc of
      Client -> return [] -- resources are created Server-side, and Client's proxies are created by the wayland library always
      Server -> liftM concat $ sequence $
        map (\ iface -> do
          let iname = interfaceName iface
              internalCName = mkName $ pname ++ "_" ++ iname ++ "_c_resource_create"
          foreignDec <- forImpD cCall unsafe "wl_resource_create" internalCName [t|Util.Client -> CInterface -> CInt -> (CUInt) -> IO $(conT $ interfaceTypeName pname iname) |]
          neatDec <- [d|$(varP $ interfaceResourceCreator pname iname) = \ client id ->
                          $(varE internalCName) client $(varE $ interfaceCInterfaceName pname iname) $(litE $ IntegerL $ fromIntegral $ interfaceVersion iface) id|]
          return $ Left foreignDec : map Left neatDec
          ) (protocolInterfaces sp)
  return $ interfaces ++ resourceCreators


-- | generate FFI for the API that enables you to receive messages
--
--   Either Dec Dec explained: Left dec for internal declarations, Right dec for external declarations (ie. those that should be exposed to the user)
generateListener :: ProtocolSpec -> Interface -> ServerClient -> Q [Either Dec Dec]
generateListener sp iface sc =
  -- Tree of possibilities:
  -- - Server
  --   => call it an Implementation or Interface. first argument is the client, second is the resource
  -- - Client
  --   => call it a Listener. first argument is the proxy
  --
  -- for each argument (we're not gonna deal with untyped objects or new_ids):
  -- - typed new_id
  --   - Client
  --     => that type as arg
  --   - Server
  --     => uint32_t  (the actual id. so that's new. dunno how to handle this. it's to be passed to wl_resource_create. maybe i should just create the resource for the server and pass that.)
  -- - anything else
  --   => the type you'd expect
  let -- declare a Listener or Interface type for this interface
      typeName :: Name
      typeName = messageListenerTypeName sc (protocolName sp) (interfaceName iface)
      pname = protocolName sp
      iname :: String
      iname = interfaceName iface
      messages :: [Message]
      messages = case sc of
                   Server -> interfaceRequests iface
                   Client -> interfaceEvents iface
      mkMessageName :: Message -> Name
      mkMessageName msg = case sc of
                       Server -> requestHaskName pname iname (messageName msg)
                       Client -> eventHaskName pname iname (messageName msg)
      mkListenerType :: Message -> TypeQ
      mkListenerType msg = case sc of
                Server -> [t|Util.Client -> $(conT $ interfaceTypeName pname iname) -> $(genMessageHaskType Nothing $ messageArguments msg)|]  -- see large comment above
                Client -> [t|$(conT $ interfaceTypeName pname iname) -> $(genMessageHaskType Nothing $ messageArguments msg)|]
      mkListenerConstr :: Message -> VarStrictTypeQ
      mkListenerConstr msg = do
        let name = mkMessageName msg
        ltype <- mkListenerType msg
        return (name, NotStrict, ltype)
      listenerType :: DecQ
      listenerType = do
        recArgs <- sequence $ map mkListenerConstr messages
        return $ DataD [] typeName [] [RecC typeName recArgs] []

      -- in the weird uint32_t new_id case, first pass the id through wl_resource_create to just get a resource
      preCompResourceCreate clientName msg fun =
        case sc of
          Client -> fun
          Server -> foldr (\(arg, idx) curFunc ->
            case arg of
              (_, NewIdArg _ itsName, _) -> preComposeAt curFunc [e|$(varE $ interfaceResourceCreator pname itsName) $(varE clientName) |] idx (length $ messageArguments msg)
              _                          -> curFunc
            ) fun (zip (messageArguments msg) [1..])

      -- instance dec: this struct better be Storable
      instanceDec :: DecsQ
      instanceDec = do
        [d|instance Storable $(conT typeName) where
            sizeOf _ = $(litE $ IntegerL $ funcSize * (fromIntegral $ length messages))
            alignment _ = $(return $ LitE $ IntegerL funcAlign)
	    peek _ = undefined  -- we shouldn't need to be able to read listeners (since we can't change them anyway)
	    poke ptr record = $(doE $ ( zipWith (\ idx msg ->
                noBindS [e|do
                  let haskFun = $(return $ VarE $ mkMessageName msg) record
                      unmarshaller fun = \x -> $(let (pats, funexp) = argTypeUnmarshaller (messageArguments msg) ([e|fun x|])
                                                 in LamE pats <$> funexp)

                  funptr <- $(case sc of -- the Server-side listeners take an extra Client argument
                                Server -> [e|$(varE $ wrapperName msg) $ \ client -> ($(preCompResourceCreate 'client msg [e|unmarshaller $ haskFun client|])) |]
                                -- the Client-side listener takes a void* user_data argument, which we throw out cause it's not a sane api.
                                Client -> [e|$(varE $ wrapperName msg) $ \ _ -> unmarshaller haskFun|])

                  pokeByteOff ptr $(litE $ IntegerL (idx * funcSize)) funptr
                |] )
              [0..] messages
              ) ++ [noBindS [e|return () |]] )
            |]


      -- FunPtr wrapper
      mkListenerCType msg = case sc of
                Server -> [t|Util.Client -> $(conT $ interfaceTypeName pname iname) -> $(genMessageWeirdCType Nothing $ messageArguments msg)|]  -- see large comment above
                Client -> [t|Ptr () -> $(conT $ interfaceTypeName pname iname) -> $(genMessageCType Nothing $ messageArguments msg)|]
      wrapperName msg = messageListenerWrapperName sc iname (messageName msg)
      wrapperDec msg = forImpD cCall unsafe "wrapper" (wrapperName msg) [t|$(mkListenerCType msg) -> IO (FunPtr ($(mkListenerCType msg))) |]

      -- bind add_listener
      haskName = requestHaskName pname iname "set_listener" -- dunno why I can't use this variable in the splice below.
      foreignName = requestInternalCName iname "c_add_listener"
      foreignDec :: Q Dec
      foreignDec = case sc of
                     -- void wl_resource_set_implementation(struct wl_resource *resource,
                     --    const void *implementation,
                     --    void *data,
                     --    wl_resource_destroy_func_t destroy);
                     -- typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource);
                     Server -> forImpD cCall unsafe "wl_resource_set_implementation" foreignName [t|$(conT $ interfaceTypeName pname iname) -> (Ptr $(conT $ typeName))  -> (Ptr ()) -> FunPtr ($(conT $ interfaceTypeName pname iname) -> IO ()) -> IO ()|]
                     -- int wl_proxy_add_listener(struct wl_proxy *proxy,
                     --    void (**implementation)(void), void *data);
                     Client -> forImpD cCall unsafe "wl_proxy_add_listener" foreignName [t|$(conT $ interfaceTypeName pname iname) -> (Ptr $(conT $ typeName))  -> (Ptr ()) -> IO CInt|]
      apiDec :: Q [Dec]
      apiDec = [d|$(varP $ requestHaskName (protocolName sp) iname "set_listener") = \ iface listener ->
                   do
                    -- malloc RAM for Listener type
                    memory <- malloc
                    -- store Listener type
                    poke memory listener
                    -- call foreign add_listener on stored Listener type
                    $(case sc of
                        Server -> [e|$(varE foreignName) iface memory nullPtr nullFunPtr|]
                        Client -> [e|errToResult <$> $(varE foreignName) iface memory nullPtr|])

                    |]

  in do
    -- Remember: Left for internal, Right for external.
    some <- sequence $ (liftM Right) listenerType : map (liftM Left . wrapperDec) messages
    other <- instanceDec
    more <- foreignDec
    last <- apiDec
    return $ some ++ (map Right other) ++ [Right more] ++ (map Right last)


generateRegistryBindInternal sp = liftM lefts $ generateRegistryBind sp
generateRegistryBindExternal sp = liftM rights $ generateRegistryBind sp

generateClientInternalListeners sp = liftM lefts $ generateListeners sp Client
generateServerInternalListeners sp = liftM lefts $ generateListeners sp Server

generateClientExternalListeners sp = liftM rights $ generateListeners sp Client
generateServerExternalListeners sp = liftM rights $ generateListeners sp Server

generateClientInternalMethods :: ProtocolSpec -> Q [Dec]
generateClientInternalMethods ps = liftM lefts $ generateMethods ps Client

generateServerInternalMethods :: ProtocolSpec -> Q [Dec]
generateServerInternalMethods ps = liftM lefts $ generateMethods ps Server

generateClientExternalMethods :: ProtocolSpec -> Q [Dec]
generateClientExternalMethods ps = liftM rights $ generateMethods ps Client

generateServerExternalMethods :: ProtocolSpec -> Q [Dec]
generateServerExternalMethods ps = liftM rights $ generateMethods ps Server

genMessageCType :: Maybe TypeQ -> [Argument] -> TypeQ
genMessageCType = genMessageType argTypeToCType

genMessageWeirdCType :: Maybe TypeQ -> [Argument] -> TypeQ
genMessageWeirdCType = genMessageType argTypeToWeirdInterfaceCType

genMessageHaskType :: Maybe TypeQ -> [Argument] -> TypeQ
genMessageHaskType = genMessageType argTypeToHaskType

genMessageType :: (Argument -> TypeQ) -> Maybe TypeQ -> [Argument] -> TypeQ
genMessageType fun Nothing args =
  foldr (\addtype curtype -> [t|$(fun addtype) -> $curtype|]) [t|IO ()|] args
genMessageType fun (Just someType) args =
  foldr (\addtype curtype -> [t|$(fun addtype) -> $curtype|]) someType args



-- | 3-tuple version of snd
snd3 :: (a,b,c) -> b
snd3 (_,b,_) = b

-- | Summable check if a given message argument is of type new_id
isNewId :: Argument -> Bool
isNewId arg = case arg of
                   (_, NewIdArg _ _, _) -> True
                   _                  -> False

boolToInt :: Bool -> Int
boolToInt True = 1
boolToInt False = 0