content: -- | Contains post-related actions, like submitting a post, getting
  --   information for an existing post, and performing moderator actions
  --   on posts.
  module Reddit.Actions.Post
    ( getPosts
    , getPosts'
    , getPostComments
    , getPostSubComments
    , getComments
    , getPostInfo
    , getPostsInfo
    , submitLink
    , submitLinkWithCaptcha
    , submitSelfPost
    , submitSelfPostWithCaptcha
    , setInboxReplies
    , savePost
    , unsavePost
    , editPost
    , deletePost
    , setPostFlair
    , removePost
    , markPostSpam
    , stickyPost
    , unstickyPost
    , setContestMode ) where
  
  import qualified Reddit.Routes as Route
  import Reddit.Types
  import Reddit.Types.Captcha
  import Reddit.Types.Comment
  import Reddit.Types.Empty
  import Reddit.Types.Listing
  import Reddit.Types.Reddit
  
  import Data.Default.Class
  import Data.Text (Text)
  import Network.API.Builder.Error (APIError(..))
  import qualified Data.Char as Char
  import qualified Data.Text as Text
  
  -- | Given a 'PostID', 'getPostInfo' will return the full details for that post.
  getPostInfo :: Monad m => PostID -> RedditT m Post
  getPostInfo p = do
    res <- getPostsInfo [p]
    case res of
      Listing _ _ [post] -> return post
      _ -> failWith $ APIError InvalidResponseError
  
  -- | Given a list of 'PostID's, 'getPostsInfo' will return another list containing
  --   the full details for all the posts. Note that Reddit's
  --   API imposes a limitation of 100 posts per request, so this function will fail immediately if given a list of more than 100 IDs.
  getPostsInfo :: Monad m => [PostID] -> RedditT m PostListing
  getPostsInfo ps =
    -- we can only get 100 posts at a time or the api shits itself
    if null $ drop 100 ps
      then do
        res <- runRoute $ Route.aboutPosts ps
        case res of
          Listing _ _ posts | sameLength posts ps ->
            return res
          _ -> failWith $ APIError InvalidResponseError
      else failWith $ APIError TooManyRequests
    where
      sameLength (_:xs) (_:ys) = sameLength xs ys
      sameLength [] [] = True
      sameLength _ _ = False
  
  -- | Get a 'PostListing' for the 'Hot' posts on the site overall.
  --   This maps to <http://reddit.com>.
  getPosts :: Monad m => RedditT m PostListing
  getPosts = getPosts' def Hot Nothing
  
  -- | Get a 'PostListing' for a specified listing.
  getPosts' :: Monad m => Options PostID -> ListingType -> Maybe SubredditName -> RedditT m PostListing
  getPosts' o l r = runRoute $ Route.postsListing o r (Text.pack $ lower $ show l)
    where lower = map Char.toLower
  
  -- | Save a post.
  savePost :: Monad m => PostID -> RedditT m ()
  savePost = nothing . runRoute . Route.savePost
  
  -- | Remove a saved post from your "saved posts" list.
  unsavePost :: Monad m => PostID -> RedditT m ()
  unsavePost = nothing . runRoute . Route.unsavePost
  
  -- | Submit a new link to Reddit.
  submitLink :: Monad m
             => SubredditName -- ^ The subreddit to which you're posting the link
             -> Text -- ^ The title of the link post
             -> Text -- ^ The link that you're posting
             -> RedditT m PostID
  submitLink r title url = do
    POSTWrapped res <- runRoute $ Route.submitLink r title url
    return res
  
  -- | Submit a new link to Reddit (answering a Captcha to prove we aren't a robot).
  submitLinkWithCaptcha :: Monad m
                        => SubredditName -- ^ The subreddit to which you're posting the link
                        -> Text -- ^ The title of the link post
                        -> Text -- ^ The link that you're posting
                        -> CaptchaID -- ^ The ID of the captcha we're answering
                        -> Text -- ^ The answer to the provided captcha
                        -> RedditT m PostID
  submitLinkWithCaptcha r title url iden captcha = do
    POSTWrapped res <- runRoute $ Route.submitLink r title url `withCaptcha` (iden, captcha)
    return res
  
  -- | Submit a new selfpost to Reddit.
  submitSelfPost :: Monad m
                 => SubredditName -- ^ The subreddit to which you're posting the selfpost
                 -> Text -- ^ The title of the selfpost
                 -> Text -- ^ The body of the selfpost
                 -> RedditT m PostID
  submitSelfPost r title postBody = do
    POSTWrapped res <- runRoute $ Route.submitSelfPost r title postBody
    return res
  
  -- | Submit a new selfpost to Reddit (answering a Captcha to prove we aren't a robot).
  submitSelfPostWithCaptcha :: Monad m
                            => SubredditName -- ^ The subreddit to which you're posting the selfpost
                            -> Text -- ^ The title of the selfpost
                            -> Text -- ^ The body of the selfpost
                            -> CaptchaID -- ^ The ID of the captcha we're answering
                            -> Text -- ^ The answer to the provided captcha
                            -> RedditT m PostID
  submitSelfPostWithCaptcha r title postBody iden captcha = do
    POSTWrapped res <- runRoute $ Route.submitSelfPost r title postBody `withCaptcha` (iden, captcha)
    return res
  
  -- | Deletes one of your own posts. Note that this is different from
  --   removing a post as a moderator action.
  deletePost :: Monad m => PostID -> RedditT m ()
  deletePost = nothing . runRoute . Route.delete
  
  -- | Set the link flair for a post you've submitted (or any post on a subreddit
  --   that you moderate).
  setPostFlair :: Monad m
               => SubredditName -- ^ The subreddit on which to set the flair
               -> PostID -- ^ The post whose flair should be set
               -> Text -- ^ The text label for the post's new flair
               -> Text -- ^ The CSS class for the post's new flair
               -> RedditT m ()
  setPostFlair r p text css = nothing $ runRoute $ Route.postFlair r p text css
  
  -- | Edit the text of a self-post.
  editPost :: Monad m => PostID -> Text -> RedditT m ()
  editPost thing text = nothing $ runRoute $ Route.edit thing text
  
  -- | Get a post and all its comments.
  getPostComments :: Monad m => PostID -> RedditT m PostComments
  getPostComments p = runRoute $ Route.getComments p Nothing
  
  -- | Get a post and a specific sub-tree of comments.
  getPostSubComments :: Monad m => PostID -> CommentID -> RedditT m PostComments
  getPostSubComments p c = runRoute $ Route.getComments p (Just c)
  
  -- | Get the comments for a post. Ignore the actual post itself.
  getComments :: Monad m => PostID -> RedditT m [CommentReference]
  getComments p = do
    PostComments _ c <- getPostComments p
    return c
  
  -- | Set the state of inbox replies for the specified thread.
  setInboxReplies :: Monad m => Bool -> PostID -> RedditT m ()
  setInboxReplies enabled = nothing . runRoute . Route.sendReplies enabled
  
  -- | Set the state of contest for the specified thread as a moderator action.
  setContestMode :: Monad m => Bool -> PostID -> RedditT m ()
  setContestMode enabled = nothing . runRoute . Route.setContestMode enabled
  
  -- | Removes a post (as a moderator action). Note that this is different
  --   from deleting a post.
  removePost :: Monad m => PostID -> RedditT m ()
  removePost = nothing . runRoute . Route.removePost False
  
  -- | Mark a post as spam as a moderator action.
  markPostSpam :: Monad m => PostID -> RedditT m ()
  markPostSpam = nothing . runRoute . Route.removePost True
  
  -- | Sticky a post on the subreddit on which it's posted.
  stickyPost :: Monad m
             => PostID -- ^ The post to be stickied
             -> Maybe Integer -- ^ The position to which it should be stickied
             -> RedditT m ()
  stickyPost p n = nothing $ runRoute $ Route.stickyPost True p n
  
  -- | Unsticky a post from the subreddit on which it's posted.
  unstickyPost :: Monad m
             => PostID -- ^ The post to be unstickied
             -> Maybe Integer -- ^ The position from which it should be unstickied
             -> RedditT m ()
  unstickyPost p n = nothing $ runRoute $ Route.stickyPost False p n
  