{-# LANGUAGE OverloadedStrings #-}

module Web.XING.API.Error
    (
      mapError
    , handleError
    , handleStatusCodeException
    ) where

import Web.XING.Types
import Network.HTTP.Types (ResponseHeaders)
import Data.Maybe (fromMaybe)
import qualified Data.ByteString.Lazy.Char8 as BSL
import qualified Data.ByteString.Char8 as BS
import Control.Applicative ((<$>), (<*>))
import Data.Aeson (decode, FromJSON(parseJSON), Value(Object) , (.:))
import Control.Exception (throw)
import Network.HTTP.Conduit (HttpException(StatusCodeException))

mapError
  :: XINGError
  -> APIError
mapError (XINGError "INVALID_OAUTH_SIGNATURE" _)        = OAuthError "Invalid oauth signature. Check your consumer and access token secret."
mapError (XINGError "INVALID_OAUTH_CONSUMER" _)         = OAuthError "Invalid oauth consumer key. Check your config."
mapError (XINGError "INSUFFICIENT_PRIVILEGES" _)        = OAuthError "Required permission missing"
mapError (XINGError "INVALID_OAUTH_VERSION" _)          = OAuthError "Invalid oauth version"
mapError (XINGError "INVALID_OAUTH_SIGNATURE_METHOD" _) = OAuthError "Invalid oauth version"
mapError (XINGError "REQUIRED_PARAMETER_MISSING" _)     = OAuthError "Required parameter missing. Should never have happened."
mapError (XINGError "INVALID_REQUEST_TOKEN" _)          = OAuthError "Invalid request token. Maybe the verifier was wrong?"
mapError (XINGError "INVALID_OAUTH_TOKEN" _)            = TokenError "The oauth token was invalid. Maybe the user revoked it?"
mapError (XINGError "TIME_EXPIRED" _)                   = OAuthError "Time was too old. Make sure that your local clock is set correctly."
mapError (XINGError "RATE_LIMIT_EXCEEDED" _)            = Throttled
mapError (XINGError "CALLBACK_URL_NOT_ALLOWED" _)       = CallError "The callback URL was not allowed" -- TOOD API shows better error message
mapError _                                              = CallError "unknown"

data XINGError =
  XINGError BSL.ByteString BSL.ByteString
  deriving (Show, Eq)

instance FromJSON XINGError where
  parseJSON (Object response) =
    XINGError <$> (response .: "error_name")
              <*> (response .: "message")
  parseJSON _ = fail "no parse"

handleStatusCodeException
  :: BS.ByteString
  -> HttpException
  -> a
handleStatusCodeException call (StatusCodeException status headers _) = throw $ handleError status headers call
handleStatusCodeException _    e                                      = throw e

handleError
  :: Status
  -> ResponseHeaders
  -> BS.ByteString
  -> APIError
handleError _ headers _ =
  case decode $ BSL.fromChunks [fromMaybe "{}" (lookup "X-Response-Body-Start" headers)] of
    Just e  -> mapError e
    Nothing -> CallError "unknown"