{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE RecordWildCards #-}
module Network.Hermes.Types where

import Control.Applicative

import Control.Concurrent.STM(TVar,TChan,TMVar)
import Data.Set(Set)
import Data.Map(Map)
import qualified Data.ByteString as B
import System.IO(Handle)
import Data.Serialize

import Network.Hermes.Protocol
import Network.Hermes.Misc
import Network.Hermes.MChan
import Codec.Crypto.RSA(PublicKey,PrivateKey)
import Codec.Crypto.AES.IO(AESCtx)

-- * Types

data CoreContext = CoreContext {
  myKey :: PublicKey
  ,myPrivateKey :: PrivateKey
  ,myHermesID :: HermesID
  ,myKeySignature :: TVar (Maybe Signature)
  ,authorities :: TVar [PublicKey] -- ^ List of keys we trust to sign other keys for indirect trust
  ,listeners :: TVar (Set ListenerAddress) -- ^ List of open ports for incoming traffic
   -- CHECKME: Would killing these actually do anything useful?
  ,listenerKillers :: TVar (Map ListenerAddress (IO ()))
  ,peerAddress :: TVar (Map HermesID Address)
  ,peerKeys :: TVar (Map HermesID PeerKey)
  ,peerFailures :: TVar (Map HermesID Int)
  ,peerConnections :: TVar (Map HermesID (TMVar Connection))
  ,trustLimit :: TVar TrustLevel -- ^ Peers with less than this level of trust won't be trusted. AdHoc or Indirect are good values.
  ,messageBox :: MChan (Type,Type,B.ByteString) (HermesID,B.ByteString)
   -- ^ This is a.. map of message type, tag type and tag value to the message origin and message
  ,timeLimit :: TVar Double -- ^ In seconds
  }

data CoreContextSnapshot = CoreContextSnapshot {
  myKeySnap :: PublicKey
  ,myPrivateKeySnap :: PrivateKey
  ,myHermesIDSnap :: HermesID
  ,myKeySignatureSnap :: Maybe Signature
  ,authoritiesSnap :: [PublicKey]
  ,peerAddressSnap :: Map HermesID Address
  ,peerKeysSnap :: Map HermesID PeerKey
  ,peerFailuresSnap :: Map HermesID Int
  ,trustLimitSnap :: TrustLevel
  ,timeLimitSnap :: Double
   } deriving(Show)

instance Serialize CoreContextSnapshot where
  put (CoreContextSnapshot a b c d e f g h i j) = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h >> put i >> put j
  get = CoreContextSnapshot <$> get <*> get <*> get <*> get <*> get <*> get <*> get <*> get <*> get <*> get

data ListenerAddress = ListenerAddress {
  localAddress :: Address -- ^ The address we bound to on this system
  ,remoteAddress :: Address -- ^ The one other peers see. May be different due, mostly, to port-forwarding
  } deriving(Eq,Ord)


-- * Cryptographic types and peers

type Signature = B.ByteString

data PeerKey = PeerKey {
  peerKey :: PublicKey
  ,trust :: TrustLevel
  ,signature :: Maybe Signature
  } deriving(Show)

instance Serialize PeerKey where
  put (PeerKey a b c) = put a >> put b >> put c
  get = PeerKey <$> get <*> get <*> get

data Connection = Connection {
  aesctx :: AESCtx
  ,aesKey :: B.ByteString
  ,handle :: Handle
  ,typeMap :: TVar (Map Type Int)
  ,typeMax :: TVar Int
  }