{-# 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

    , getContextSinksM
    , getContextSinkByNameM
    , getContextSinkByIndexM
    )
where


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

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

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

import Control.Monad (void)
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 99 "src/Sound/Pulse/Sinkinfo.hsc" #-}
    alignment _ = (8)
{-# LINE 100 "src/Sound/Pulse/Sinkinfo.hsc" #-}
    peek p = Sinkinfo
       <$> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 0) p)
{-# LINE 102 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 8) p
{-# LINE 103 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 16) p)
{-# LINE 104 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 24) p
{-# LINE 105 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 36) p
{-# LINE 106 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 168) p
{-# LINE 107 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 172) p
{-# LINE 108 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> ((/= (0 :: CInt)) <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 109 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 308) p
{-# LINE 110 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 312) p)
{-# LINE 111 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 320) p
{-# LINE 112 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (peekCString =<< (\hsc_ptr -> peekByteOff hsc_ptr 328) p)
{-# LINE 113 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (sinkFlagssFromInt <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 114 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 344) p
{-# LINE 115 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 352) p
{-# LINE 116 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 360) p
{-# LINE 117 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (sinkStateFromInt <$> ((\hsc_ptr -> peekByteOff hsc_ptr 304) p))
{-# LINE 118 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 368) p
{-# LINE 119 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 372) p
{-# LINE 120 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> do
           size :: Word8 <- (\hsc_ptr -> peekByteOff hsc_ptr 376) p
{-# LINE 122 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           ptr <- (\hsc_ptr -> peekByteOff hsc_ptr 384) p
{-# LINE 123 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           mapM (peekElemOff ptr . fromIntegral) [0.. size - 1]
       <*> (\hsc_ptr -> peekByteOff hsc_ptr 392) p
{-# LINE 125 "src/Sound/Pulse/Sinkinfo.hsc" #-}
       <*> do
           size :: Word8 <- (\hsc_ptr -> peekByteOff hsc_ptr 400) p
{-# LINE 127 "src/Sound/Pulse/Sinkinfo.hsc" #-}
           ptr :: Ptr (Ptr FormatInfo) <- (\hsc_ptr -> peekByteOff hsc_ptr 408) p
{-# LINE 128 "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)

getContextSinksM :: Pulse [Sinkinfo]
getContextSinksM = pulseListM (\c cb e -> void $ getContextSinks c cb e)

-- |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))

getContextSinkByNameM :: String -> Pulse Sinkinfo
getContextSinkByNameM name =
    Pulse (\cxt cb -> void $ getContextSinkByName cxt name cb)

-- |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)

getContextSinkByIndexM :: Word32 -> Pulse Sinkinfo
getContextSinkByIndexM index =
    Pulse (\cxt cb -> void $ getContextSinkByIndex cxt index cb)