module Conjure.Types
    ( module Conjure.Types
    , PeerId (..)
    ) where

import Conjure.FileSystem.InterfaceType (TorrentHandle)
import Control.Concurrent.STM
import Control.Exception
import Data.Array.Diff
import Network.URI
import Data.IntMap (IntMap)
import System.IO
import Data.FastPackedString (FastString)
import Conjure.Protocol.PWP.Types

type Piecemap = DiffUArray Int Bool
type Blockmap = DiffUArray Int Bool

type Usecount = DiffUArray Int Int

data Torrent
    = Torrent
    { tAnnounce     :: URI
    , tAnnounceList :: [URI]
    , tComment      :: String
    , tCreatedBy    :: Maybe String
--    , tCreationData :: ? -- FIXME
    , tInfo         :: TorrentInfo
    , tInfoHash     :: FastString
    } deriving Show

data TorrentInfo
    = SingleFile
    { tLength      :: Int
    , tName        :: String
    , tPieceLength :: Int
    , tPieces      :: FastString }
    | MultiFile
    { tFiles       :: [TorrentFile]
    , tName        :: String
    , tPieceLength :: Int
    , tPieces      :: FastString
    } deriving Show

data TorrentFile
    = TorrentFile
    { fileLength :: Int
    , filePath   :: FilePath
    } deriving Show


data PeerCtrl
    = NewInput Message     -- Received a new message.
    | Reallocate           -- Cancel the current block and request another.
    | LostPiece            -- Piece failed validation. Recheck interest.
    | GotPiece Int         -- Piece passed validation. Notify remote peer.
    | ChokePeer
    | UnchokePeer
    | StartDownload
    | Disconnect           -- Cancel the current block and disconnect.
    | SockError Exception  -- Error occurred while waiting for input.
      deriving Show

data ConnectedPeer
    = ConnectedPeer
    { cpMsgChan         :: TChan PeerCtrl
    , cpPeerId          :: PeerId
    , cpTorrent         :: Torrent
    , cpPiecemap        :: TVar Piecemap
    , cpChokeStatus     :: TVar (Bool, Bool)
    , cpInterest        :: TVar (Bool, Bool)
    , cpLastDownload    :: TVar (Maybe Integer)
    , cpLastUpload      :: TVar (Maybe Integer)
    -- Pending download/upload. Used in STM to indicate
    -- a peer marked for download or upload but possibly
    -- hasn't started the transaction yet.
    , cpPendingDownload :: TVar Bool
    , cpPendingUpload   :: TVar Bool
    }

instance Eq ConnectedPeer where
    cp1 == cp2 = cpPeerId cp1 == cpPeerId cp2



data ActiveTorrent
    = ActiveTorrent
    { atTorrent    :: Torrent
    , atHandle     :: TorrentHandle
    , atPeerId     :: PeerId
    , atUsecount   :: TVar Usecount
    , atPiecemap   :: TVar Piecemap
    , atPieces     :: TVar (IntMap Piece)
    , atPeers      :: TVar [ConnectedPeer] -- Use a Set?
    , atUploaded   :: TVar Integer
    , atDownloaded :: TVar Integer
    , atLeft       :: TVar Integer
    }

data BlockStatus
    = Active [ConnectedPeer]
    | Downloaded

instance Show BlockStatus where
    show (Active lst) = "(Active " ++ show (length lst) ++ ")"
    show Downloaded = "Downloaded"

data Piece
    = Piece
    { pIndex  :: Int
    , pStatus :: TVar [BlockStatus]
    }

type Block = (Piece,Int,Int) -- (Piece, offset, length)


