    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE EmptyDataDecls #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    module Web.Twitter.Conduit.Cursor
           ( CursorKey (..)
           , IdsCursorKey
           , UsersCursorKey
           , ListsCursorKey
           , EventsCursorKey
           , WithCursor (..)
           ) where

    import Data.Aeson
    import Data.Text (Text)
    import Web.Twitter.Types (checkError)

    -- $setup
    -- >>> type UserId = Integer

    class CursorKey a where
        cursorKey :: a -> Text

    -- | Phantom type to specify the key which point out the content in the response.
    data IdsCursorKey
    instance CursorKey IdsCursorKey where
        cursorKey :: IdsCursorKey -> Text
    cursorKey = Text -> IdsCursorKey -> Text
    forall a b. a -> b -> a
    const "ids"

    -- | Phantom type to specify the key which point out the content in the response.
    data UsersCursorKey
    instance CursorKey UsersCursorKey where
        cursorKey :: UsersCursorKey -> Text
    cursorKey = Text -> UsersCursorKey -> Text
    forall a b. a -> b -> a
    const "users"

    -- | Phantom type to specify the key which point out the content in the response.
    data ListsCursorKey
    instance CursorKey ListsCursorKey where
        cursorKey :: ListsCursorKey -> Text
    cursorKey = Text -> ListsCursorKey -> Text
    forall a b. a -> b -> a
    const "lists"

    data EventsCursorKey
    instance CursorKey EventsCursorKey where
        cursorKey :: EventsCursorKey -> Text
    cursorKey = Text -> EventsCursorKey -> Text
    forall a b. a -> b -> a
    const "events"

    -- | A wrapper for API responses which have "next_cursor" field.
    --
    -- The first type parameter of 'WithCursor' specifies the field name of contents.
    --
    -- >>> let Just res = decode "{\"previous_cursor\": 0, \"next_cursor\": 1234567890, \"ids\": [1111111111]}" :: Maybe (WithCursor Integer IdsCursorKey UserId)
    -- >>> nextCursor res
    -- Just 1234567890
    -- >>> contents res
    -- [1111111111]
    --
    -- >>> let Just res = decode "{\"previous_cursor\": 0, \"next_cursor\": 0, \"users\": [1000]}" :: Maybe (WithCursor Integer UsersCursorKey UserId)
    -- >>> nextCursor res
    -- Just 0
    -- >>> contents res
    -- [1000]
    --
    -- >>> let Just res = decode "{\"next_cursor\": \"hogehoge\", \"events\": [1000]}" :: Maybe (WithCursor Text EventsCursorKey UserId)
    -- >>> nextCursor res
    -- Just "hogehoge"
    -- >>> contents res
    -- [1000]
    data WithCursor cursorType cursorKey wrapped = WithCursor
        { WithCursor cursorType cursorKey wrapped -> Maybe cursorType
    previousCursor :: Maybe cursorType
        , WithCursor cursorType cursorKey wrapped -> Maybe cursorType
    nextCursor :: Maybe cursorType
        , WithCursor cursorType cursorKey wrapped -> [wrapped]
    contents :: [wrapped]
        } deriving Int -> WithCursor cursorType cursorKey wrapped -> ShowS
    [WithCursor cursorType cursorKey wrapped] -> ShowS
    WithCursor cursorType cursorKey wrapped -> String
    (Int -> WithCursor cursorType cursorKey wrapped -> ShowS)
    -> (WithCursor cursorType cursorKey wrapped -> String)
    -> ([WithCursor cursorType cursorKey wrapped] -> ShowS)
    -> Show (WithCursor cursorType cursorKey wrapped)
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    Int -> WithCursor cursorType cursorKey wrapped -> ShowS
    forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    [WithCursor cursorType cursorKey wrapped] -> ShowS
    forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    WithCursor cursorType cursorKey wrapped -> String
    showList :: [WithCursor cursorType cursorKey wrapped] -> ShowS
    $cshowList :: forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    [WithCursor cursorType cursorKey wrapped] -> ShowS
    show :: WithCursor cursorType cursorKey wrapped -> String
    $cshow :: forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    WithCursor cursorType cursorKey wrapped -> String
    showsPrec :: Int -> WithCursor cursorType cursorKey wrapped -> ShowS
    $cshowsPrec :: forall cursorType cursorKey wrapped.
    (Show cursorType, Show wrapped) =>
    Int -> WithCursor cursorType cursorKey wrapped -> ShowS
    Show

    instance (FromJSON wrapped, FromJSON ct, CursorKey c) =>
             FromJSON (WithCursor ct c wrapped) where
        parseJSON :: Value -> Parser (WithCursor ct c wrapped)
    parseJSON (Object o :: Object
    o) = Object -> Parser ()
    checkError Object
    o Parser ()
    -> Parser (WithCursor ct c wrapped)
    -> Parser (WithCursor ct c wrapped)
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >>
          Maybe ct -> Maybe ct -> [wrapped] -> WithCursor ct c wrapped
    forall cursorType cursorKey wrapped.
    Maybe cursorType
    -> Maybe cursorType
    -> [wrapped]
    -> WithCursor cursorType cursorKey wrapped
    WithCursor (Maybe ct -> Maybe ct -> [wrapped] -> WithCursor ct c wrapped)
    -> Parser (Maybe ct)
    -> Parser (Maybe ct -> [wrapped] -> WithCursor ct c wrapped)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Object
    o Object -> Text -> Parser (Maybe ct)
    forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
    .:? "previous_cursor"
                     Parser (Maybe ct -> [wrapped] -> WithCursor ct c wrapped)
    -> Parser (Maybe ct)
    -> Parser ([wrapped] -> WithCursor ct c wrapped)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Object
    o Object -> Text -> Parser (Maybe ct)
    forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
    .:? "next_cursor"
                     Parser ([wrapped] -> WithCursor ct c wrapped)
    -> Parser [wrapped] -> Parser (WithCursor ct c wrapped)
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> Object
    o Object -> Text -> Parser [wrapped]
    forall a. FromJSON a => Object -> Text -> Parser a
    .:  c -> Text
    forall a. CursorKey a => a -> Text
    cursorKey (c
    forall a. HasCallStack => a
    undefined :: c)
        parseJSON _ = Parser (WithCursor ct c wrapped)
    forall a. Monoid a => a
    mempty