module Resolve.DNS.Server.UDP where

import Resolve.Types

import Resolve.DNS.Types
import Resolve.DNS.Server.Types
import Data.ByteString
import qualified Data.ByteString.Lazy as BSL
import Data.Typeable

import qualified Resolve.DNS.Decode as D
import qualified Resolve.DNS.Encode as E

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import Control.Exception




data DecodeError = DecodeError String
  deriving (Typeable, Show)

instance Exception DecodeError where
  toException = serverExceptionToException
  fromException = serverExceptionFromException

data EncodeError = EncodeError String
  deriving (Typeable, Show)

instance Exception EncodeError where
  toException = serverExceptionToException
  fromException = serverExceptionFromException

data ResponseTooLong = ResponseTooLong
  deriving (Typeable, Show)

instance Exception ResponseTooLong where
  toException = serverExceptionToException
  fromException = serverExceptionFromException

maxLength = 512

encodeMessage :: Message -> BSL.ByteString
encodeMessage m = case E.encode E.message m of
  Left e -> throw $ EncodeError e
  Right b -> b

resolve :: Resolve Message Message -> Resolve ByteString ByteString
resolve r a = do
  a' <- case D.decodeMessage a of
    Left e -> throw $ DecodeError e
    Right a' -> return a'
  b' <- r a'

  let b = encodeMessage b'

  BSL.toStrict <$> if (BSL.null $ BSL.drop maxLength b) then
        return $ b
    else do
    let b_tc = encodeMessage $ b' { header = (header b') { tc = True }
                                  , question = question b'
                                  , answer = []
                                  , authority = []
                                  , additional = []
                                 }
    if (BSL.null $ BSL.drop maxLength b_tc) then
      return $ b_tc
      else
      throw ResponseTooLong