{-# LANGUAGE ScopedTypeVariables #-}

-- |
-- Module      :  BitTorrent
-- Copyright   :  (c) Alexandru Scvortov 2009
-- License     :  LGPL (see LICENSE file)
-- Maintainer  :  scvalex@gmail.com
--
-- This module centralizes the functions.  As a rule of thumb, this
-- should be the only module that you need to import in order to use
-- the BitTorrent library.
--
-- This does NOT include any of the concurrent stuff, network stuff or
-- managers.
--

module BitTorrent
    ( Metainfo(..), InfoHash, readMetainfo, parseMetainfo
    , PeerId, makeMyPeerId, translatePeerId
    , getLTorrentDir, getDefaultDownloadDir
    , createFilePathIfMissing, (</>), calculateFileChecksum
    , Peer(..), Handshake(..), Message(..), newPeerIO, newPeerSTM
    , setPeerChocked, setPeerInterested, setPiecemap, readPiecemap
    , hPutHandshake, hGetHandshake, hGetMessage, hPutMessage
    , Entity(..)
    , Piecemap, makePiecemap
    , PieceStatus(..), PieceStatusArray
    , makeInitialRequest, TrackerRequest(..), TrackerResponse(..)
    , getPeers, doTrackerQuery, getCompleteIncomplete
    , readConfig, writeConfig, writeConfigIfMissing
    , readConfigDefault
    ) where

import Prelude hiding ( catch )

import BitTorrent.Peer
import BitTorrent.Tracker
import Control.Concurrent
import Control.Exception
import Control.Monad.Trans
import Data.Array.Unboxed
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Metainfo
import Data.PeerId
import Data.Piecemap
import Network.Entity
import System.Configuration
import System.Directory ( getUserDocumentsDirectory )
import System.Directory.Extra
import System.IO
import Text.Printf ( printf )

-- | Read and parse a metainfo file.
readMetainfo :: FilePath -> IO Metainfo
readMetainfo f = do
  bracket (openBinaryFile f ReadMode)
          (hClose)
          (\h -> do
             txt <- L.hGetContents h
             case parseMetainfo txt of
               Nothing -> fail $ printf "readMetainfo: could not parse ``%s''" f
               Just mi -> return mi)

-- | Lift an action from IO to a MonadIO.
io :: MonadIO m => IO a -> m a
io = liftIO

-- | Return the path to the user's default download directory.
getDefaultDownloadDir :: MonadIO m => m FilePath
getDefaultDownloadDir = do
  docs <- io $ getUserDocumentsDirectory
  return $ docs </> "downloads"

-- | The current status of a piece.
data PieceStatus = Complete -- ^ The piece has been downloaded and checked
                 | DontHave -- ^ The piece has not been downloaded yet
                 | Getting [ThreadId] -- ^ One or more peer handlers is 
                                  -- downloading this piece
                   deriving (Show, Eq)

type PieceStatusArray = Array Int PieceStatus
