{-# LANGUAGE DataKinds                   #-}
{-# LANGUAGE DeriveGeneric               #-}
{-# LANGUAGE FlexibleInstances           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving  #-}
{-# LANGUAGE LambdaCase                  #-}
{-# LANGUAGE NoImplicitPrelude           #-}
{-# LANGUAGE OverloadedStrings           #-}
{-# LANGUAGE RecordWildCards             #-}
{-# LANGUAGE TypeFamilies                #-}

{-# OPTIONS_GHC -fno-warn-unused-imports #-}

-- Module      : Network.AWS.SNS.Publish
-- Copyright   : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
-- License     : This Source Code Form is subject to the terms of
--               the Mozilla Public License, v. 2.0.
--               A copy of the MPL can be found in the LICENSE file or
--               you can obtain it at http://mozilla.org/MPL/2.0/.
-- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--
-- Derived from AWS service descriptions, licensed under Apache 2.0.

-- | Sends a message to all of a topic's subscribed endpoints. When a 'messageId' is
-- returned, the message has been saved and Amazon SNS will attempt to deliver
-- it to the topic's subscribers shortly. The format of the outgoing message to
-- each subscribed endpoint depends on the notification protocol selected.
--
-- To use the 'Publish' action for sending a message to a mobile endpoint, such
-- as an app on a Kindle device or mobile phone, you must specify the
-- EndpointArn. The EndpointArn is returned when making a call with the 'CreatePlatformEndpoint' action. The second example below shows a request and response for publishing
-- to a mobile endpoint.
--
-- <http://docs.aws.amazon.com/sns/latest/api/API_Publish.html>
module Network.AWS.SNS.Publish
    (
    -- * Request
      Publish
    -- ** Request constructor
    , publish
    -- ** Request lenses
    , pMessage
    , pMessageAttributes
    , pMessageStructure
    , pSubject
    , pTargetArn
    , pTopicArn

    -- * Response
    , PublishResponse
    -- ** Response constructor
    , publishResponse
    -- ** Response lenses
    , prMessageId
    ) where

import Network.AWS.Prelude
import Network.AWS.Request.Query
import Network.AWS.SNS.Types
import qualified GHC.Exts

data Publish = Publish
    { _pMessage           :: Text
    , _pMessageAttributes :: EMap "entry" "Name" "Value" Text MessageAttributeValue
    , _pMessageStructure  :: Maybe Text
    , _pSubject           :: Maybe Text
    , _pTargetArn         :: Maybe Text
    , _pTopicArn          :: Maybe Text
    } deriving (Eq, Show)

-- | 'Publish' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'pMessage' @::@ 'Text'
--
-- * 'pMessageAttributes' @::@ 'HashMap' 'Text' 'MessageAttributeValue'
--
-- * 'pMessageStructure' @::@ 'Maybe' 'Text'
--
-- * 'pSubject' @::@ 'Maybe' 'Text'
--
-- * 'pTargetArn' @::@ 'Maybe' 'Text'
--
-- * 'pTopicArn' @::@ 'Maybe' 'Text'
--
publish :: Text -- ^ 'pMessage'
        -> Publish
publish p1 = Publish
    { _pMessage           = p1
    , _pTopicArn          = Nothing
    , _pTargetArn         = Nothing
    , _pSubject           = Nothing
    , _pMessageStructure  = Nothing
    , _pMessageAttributes = mempty
    }

-- | The message you want to send to the topic.
--
-- If you want to send the same message to all transport protocols, include the
-- text of the message as a String value.
--
-- If you want to send different messages for each transport protocol, set the
-- value of the 'MessageStructure' parameter to 'json' and use a JSON object for the 'Message' parameter. See the Examples section for the format of the JSON
-- object.
--
-- Constraints: Messages must be UTF-8 encoded strings at most 256 KB in size
-- (262144 bytes, not 262144 characters).
--
-- JSON-specific constraints:  Keys in the JSON object that correspond to
-- supported transport protocols must have simple JSON string values.  The
-- values will be parsed (unescaped) before they are used in outgoing messages. Outbound notifications are JSON encoded (meaning that the characters will be reescaped for sending).
-- Values have a minimum length of 0 (the empty string, "", is allowed). Values
-- have a maximum length bounded by the overall message size (so, including
-- multiple protocols may limit message sizes). Non-string values will cause the
-- key to be ignored. Keys that do not correspond to supported transport
-- protocols are ignored. Duplicate keys are not allowed. Failure to parse or
-- validate any key or value in the message will cause the 'Publish' call to
-- return an error (no partial delivery).
pMessage :: Lens' Publish Text
pMessage = lens _pMessage (\s a -> s { _pMessage = a })

-- | Message attributes for Publish action.
pMessageAttributes :: Lens' Publish (HashMap Text MessageAttributeValue)
pMessageAttributes =
    lens _pMessageAttributes (\s a -> s { _pMessageAttributes = a })
        . _EMap

-- | Set 'MessageStructure' to 'json' if you want to send a different message for each
-- protocol. For example, using one publish action, you can send a short message
-- to your SMS subscribers and a longer message to your email subscribers. If
-- you set 'MessageStructure' to 'json', the value of the 'Message' parameter must:
--
-- be a syntactically valid JSON object; and contain at least a top-level JSON
-- key of "default" with a value that is a string.   You can define other
-- top-level keys that define the message you want to send to a specific
-- transport protocol (e.g., "http").
--
-- For information about sending different messages for each protocol using the
-- AWS Management Console, go to <http://docs.aws.amazon.com/sns/latest/gsg/Publish.html#sns-message-formatting-by-protocol Create Different Messages for Each Protocol> in
-- the /Amazon Simple Notification Service Getting Started Guide/.
--
-- Valid value: 'json'
pMessageStructure :: Lens' Publish (Maybe Text)
pMessageStructure =
    lens _pMessageStructure (\s a -> s { _pMessageStructure = a })

-- | Optional parameter to be used as the "Subject" line when the message is
-- delivered to email endpoints. This field will also be included, if present,
-- in the standard JSON messages delivered to other endpoints.
--
-- Constraints: Subjects must be ASCII text that begins with a letter, number,
-- or punctuation mark; must not include line breaks or control characters; and
-- must be less than 100 characters long.
pSubject :: Lens' Publish (Maybe Text)
pSubject = lens _pSubject (\s a -> s { _pSubject = a })

-- | Either TopicArn or EndpointArn, but not both.
pTargetArn :: Lens' Publish (Maybe Text)
pTargetArn = lens _pTargetArn (\s a -> s { _pTargetArn = a })

-- | The topic you want to publish to.
pTopicArn :: Lens' Publish (Maybe Text)
pTopicArn = lens _pTopicArn (\s a -> s { _pTopicArn = a })

newtype PublishResponse = PublishResponse
    { _prMessageId :: Maybe Text
    } deriving (Eq, Ord, Show, Monoid)

-- | 'PublishResponse' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'prMessageId' @::@ 'Maybe' 'Text'
--
publishResponse :: PublishResponse
publishResponse = PublishResponse
    { _prMessageId = Nothing
    }

-- | Unique identifier assigned to the published message.
--
-- Length Constraint: Maximum 100 characters
prMessageId :: Lens' PublishResponse (Maybe Text)
prMessageId = lens _prMessageId (\s a -> s { _prMessageId = a })

instance ToPath Publish where
    toPath = const "/"

instance ToQuery Publish where
    toQuery Publish{..} = mconcat
        [ "Message"           =? _pMessage
        , "MessageAttributes" =? _pMessageAttributes
        , "MessageStructure"  =? _pMessageStructure
        , "Subject"           =? _pSubject
        , "TargetArn"         =? _pTargetArn
        , "TopicArn"          =? _pTopicArn
        ]

instance ToHeaders Publish

instance AWSRequest Publish where
    type Sv Publish = SNS
    type Rs Publish = PublishResponse

    request  = post "Publish"
    response = xmlResponse

instance FromXML PublishResponse where
    parseXML = withElement "PublishResult" $ \x -> PublishResponse
        <$> x .@? "MessageId"