{-# LINE 1 "src/Sound/Pulse/Sinkinfo.hsc" #-}
{-
{-# LINE 2 "src/Sound/Pulse/Sinkinfo.hsc" #-}
    Copyright 2016 Markus Ongyerth

    This file is part of pulseaudio-hs.

    Monky is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Monky is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pulseaudio-hs.  If not, see <http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}
{-|
Module      : Sound.Pulse.Sinkinfo
Description : provides the time type used for pa_sink_info.
Maintianer  : ongy
Stability   : experimental
-}
module Sound.Pulse.Sinkinfo
    ( SinkFlags(..)
    , SinkState(..)
    , Sinkinfo(..)

    , getContextSinks
    , getContextSinkByName
    , getContextSinkByIndex
    )
where


{-# LINE 41 "src/Sound/Pulse/Sinkinfo.hsc" #-}

{-# LINE 42 "src/Sound/Pulse/Sinkinfo.hsc" #-}

import Control.Applicative ((<$>), (<*>))
import Sound.Pulse.Volume
import Sound.Pulse.Operation
import Sound.Pulse.Userdata
import Data.Word (Word32, Word8, Word)

import Foreign.Ptr (Ptr, FunPtr, freeHaskellFunPtr, castFunPtrToPtr, castPtrToFunPtr)
import Foreign.C.Types (CInt(..), CUInt(..))
import Foreign.C.String (peekCString, withCString, CString)
import Foreign.Storable (Storable(..))

import Sound.Pulse.Context (Context)
import Sound.Pulse.ChannelPosition
import Sound.Pulse.SampleSpec

import Sound.Pulse.Def (SinkFlags(..), sinkFlagssFromInt, SinkState(..), sinkStateFromInt)

data PropList -- TODO :)

data FormatInfo -- TODO
data SinkPortInfo -- TODO

-- |Type used for pa_sink_info
data Sinkinfo = Sinkinfo
    { siName              :: String
    , siIndex             :: Word32
    , siDescription       :: String
    , siSampleSpec        :: SampleSpec
    , siChannelMap        :: ChannelMap
    , siOwnerModule       :: Word32
    , siVolume            :: CVolume
    , siMute              :: Bool
    , siMonitorSource     :: Word32
    , siMonitorSourceName :: String
    , siLatency           :: Word
    , siDriver            :: String
    , siFlags             :: [SinkFlags]
    , siProplist          :: Ptr PropList
    , siConfiguredLatency :: Word
    , siBaseVolume        :: Volume
    , siState             :: SinkState
    , siVolumeSteps       :: Word32
    , siCard              :: Word32
    , siPorts             :: [Ptr SinkPortInfo]
    , siActivePort        :: Ptr SinkPortInfo
    , siFormats           :: [Ptr FormatInfo]
    } deriving (Eq, Show)

instance Storable Sinkinfo where
    sizeOf _ = (416)
{-# LINE 93 "src/Sound/Pulse/Sinkinfo.hsc" #-}
    alignment _ = (8)
{-# LINE 94 "src/Sound/Pulse/Sinkinfo.hsc" #-}
    peek p = Sinkinfo
       <$> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 0) p)
{-# LINE 96 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) p
{-# LINE 97 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 16) p)
{-# LINE 98 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 24) p
{-# LINE 99 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 36) p
{-# LINE 100 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 168) p
{-# LINE 101 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 172) p
{-# LINE 102 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> ((/= (0 :: CInt)) <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 103 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 308) p
{-# LINE 104 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 312) p)
{-# LINE 105 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 320) p
{-# LINE 106 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 328) p)
{-# LINE 107 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (sinkFlagssFromInt <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 108 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 344) p
{-# LINE 109 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 352) p
{-# LINE 110 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 360) p
{-# LINE 111 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (sinkStateFromInt <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 112 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 368) p
{-# LINE 113 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 372) p
{-# LINE 114 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> do
           size :: Word8 <- (\hsc_ptr -> peekByteOff hsc_ptr 376) p
{-# LINE 116 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           ptr <- (\hsc_ptr -> peekByteOff hsc_ptr 384) p
{-# LINE 117 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           mapM (peekElemOff ptr . fromIntegral) [0.. size - 1]
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 392) p
{-# LINE 119 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> do
           size :: Word8 <- (\hsc_ptr -> peekByteOff hsc_ptr 400) p
{-# LINE 121 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           ptr :: Ptr (Ptr FormatInfo) <- (\hsc_ptr -> peekByteOff hsc_ptr 408) p
{-# LINE 122 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           mapM (peekElemOff ptr . fromIntegral) [0.. size - 1]
    poke _ (Sinkinfo {..}) = error "PA: Currently no sinkinfo poke"

type SinkinfoCB = Context -> Ptr Sinkinfo -> CInt -> Ptr Userdata -> IO ()
foreign import ccall "wrapper" mkSinkinfoCB :: SinkinfoCB -> IO (FunPtr SinkinfoCB)

foreign import ccall "pa_context_get_sink_info_list" pa_context_get_sink_info_list :: Context -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)

foreign import ccall "pa_context_get_sink_info_by_name" pa_context_get_sink_info_by_name :: Context -> CString -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)

foreign import ccall "pa_context_get_sink_info_by_index" pa_context_get_sink_info_by_index :: Context -> CUInt -> FunPtr SinkinfoCB -> Ptr Userdata -> IO (Ptr UOperation)

mkCallback :: (Sinkinfo -> IO ()) -> IO () -> IO (FunPtr SinkinfoCB)
mkCallback fun endf = mkSinkinfoCB $
    \_ ptr end fP -> if end == 0
        then fun =<< peek ptr
        else do
            endf -- Call the user end function
            -- free the FunPtr defiend here
            freeHaskellFunPtr (castPtrToFunPtr fP)

-- |Get all sinks from a context.
getContextSinks
    :: Context -- ^The context
    -> (Sinkinfo -> IO ()) -- ^List callback. Will be called once per list entry
    -> IO () -- ^End callback. Will be called once after all list entries
    -> IO Operation
getContextSinks cxt fun endf = do
    funP <- mkCallback fun endf
    ptrToOperation =<< pa_context_get_sink_info_list cxt funP (castFunPtrToPtr funP)

-- |Get a sink by name
getContextSinkByName
    :: Context
    -> String
    -> (Sinkinfo -> IO ())
    -> IO Operation
getContextSinkByName cxt name fun = do
    funP <- mkCallback fun (return ())
    ptrToOperation =<< withCString name (\ptr -> pa_context_get_sink_info_by_name cxt ptr funP (castFunPtrToPtr funP))

-- |Get a sink by index
getContextSinkByIndex
    :: Context
    -> Word32
    -> (Sinkinfo -> IO ())
    -> IO Operation
getContextSinkByIndex cxt idx fun = do
    funP <- mkCallback fun (return ())
    ptrToOperation =<< pa_context_get_sink_info_by_index cxt (fromIntegral idx) funP (castFunPtrToPtr funP)