content: {-# OPTIONS_GHC -XFlexibleInstances -XTypeSynonymInstances #-}
  
  {- Channel basics for HSH
  Copyright (C) 2004-2008 John Goerzen <jgoerzen@complete.org>
  Please see the COPYRIGHT file
  -}
  
  {- |
     Module     : HSH.Channel
     Copyright  : Copyright (C) 2006-2009 John Goerzen
     License    : GNU LGPL, version 2.1 or above
  
     Maintainer : John Goerzen <jgoerzen@complete.org>
     Stability  : provisional
     Portability: portable
  
  Copyright (c) 2006-2009 John Goerzen, jgoerzen\@complete.org
  -}
  
  module HSH.Channel (Channel(..),
                      chanAsString,
                      chanAsBSL,
                      chanAsBS,
                      chanToHandle,
                      Channelizable(..)
                     ) where
  
  import qualified Data.ByteString.Lazy as BSL
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.Lazy.Char8 as BSLC
  import System.IO
  import Control.Concurrent
  
  {- | The main type for communicating between commands.  All are expected to
  be lazy. -}
  data Channel = ChanString String
               | ChanBSL BSL.ByteString
               | ChanHandle Handle
  
  chanAsString :: Channel -> IO String
  chanAsString (ChanString s) = return s
  chanAsString (ChanBSL s) = return . bsl2str $ s
  chanAsString (ChanHandle h) = hGetContents h
  
  chanAsBSL :: Channel -> IO BSL.ByteString
  chanAsBSL (ChanString s) = return . str2bsl $ s
  chanAsBSL (ChanBSL s) = return s
  chanAsBSL (ChanHandle h) = BSL.hGetContents h
  
  chanAsBS :: Channel -> IO BS.ByteString
  chanAsBS c = do r <- chanAsBSL c
                  let contents = BSL.toChunks r
                  return . BS.concat $ contents
  
  {- | Writes the Channel to the given Handle. If the first parameter is True,
       do this in a separate thread and close the handle afterwards.
  -}
  chanToHandle :: Bool -> Channel -> Handle -> IO ()
  chanToHandle close c h = if close then forkIO (dumpChanToHandle c h >> hClose h) >> return ()
                                    else dumpChanToHandle c h
     where dumpChanToHandle (ChanString s) h = hPutStr h s
           dumpChanToHandle (ChanBSL s) h = BSL.hPut h s
           dumpChanToHandle (ChanHandle srchdl) desthdl
                = BSL.hGetContents srchdl >>= BSL.hPut desthdl
  
  class Channelizable a where
      toChannel :: a -> Channel
  instance Channelizable String where
      toChannel = ChanString
  instance Channelizable BSL.ByteString where
      toChannel = ChanBSL
  instance Channelizable Handle where
      toChannel = ChanHandle
  instance Channelizable BS.ByteString where
      toChannel bs = ChanBSL . BSL.fromChunks $ [bs]
  
  
                      
  str2bsl :: String -> BSL.ByteString
  str2bsl = BSLC.pack
  
  bsl2str :: BSL.ByteString -> String
  bsl2str = BSLC.unpack
  
  