    -- | This module exists just to facilitate testing.
    -- /Nothing here is part of the OEIS API./

    module Math.OEIS.Internal where

    --------------------------------------------------------------------------------

    import Control.Arrow (second, (***))
    import Data.Char     (isSpace, toUpper, toLower)
    import Data.List     (intercalate, isPrefixOf, foldl')
    import Network.HTTP  (simpleHTTP, rspBody, rspCode, rqBody, rqHeaders, rqMethod, rqURI, Request(..), RequestMethod(GET))
    import Network.URI   (parseURI, URI)

    import Math.OEIS.Types

    --------------------------------------------------------------------------------

    baseSearchURI :: String
    baseSearchURI :: String
    baseSearchURI = String
    "http://oeis.org/search?fmt=text&q="

    idSearchURI :: String -> String
    idSearchURI :: String -> String
    idSearchURI String
    n = String
    baseSearchURI String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "id:" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    n

    seqSearchURI :: SequenceData -> String
    seqSearchURI :: SequenceData -> String
    seqSearchURI SequenceData
    xs = String
    baseSearchURI String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "," ((Integer -> String) -> SequenceData -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map Integer -> String
    forall a. Show a => a -> String
    show SequenceData
    xs)

    getOEIS :: (a -> String) -> a -> IO [OEISSequence]
    getOEIS :: forall a. (a -> String) -> a -> IO [OEISSequence]
    getOEIS a -> String
    toURI a
    key =
        case String -> Maybe URI
    parseURI (a -> String
    toURI a
    key) of
          Maybe URI
    Nothing  -> [OEISSequence] -> IO [OEISSequence]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return []
          Just URI
    uri -> do
              Maybe String
    mbody <- URI -> IO (Maybe String)
    get URI
    uri
              [OEISSequence] -> IO [OEISSequence]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([OEISSequence] -> IO [OEISSequence])
    -> [OEISSequence] -> IO [OEISSequence]
    forall a b. (a -> b) -> a -> b
    $ [OEISSequence]
    -> (String -> [OEISSequence]) -> Maybe String -> [OEISSequence]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe [] String -> [OEISSequence]
    parseOEIS Maybe String
    mbody

    get :: URI -> IO (Maybe String)
    get :: URI -> IO (Maybe String)
    get URI
    uri = do
        Result (Response String)
    ersp <- Request String -> IO (Result (Response String))
    forall ty. HStream ty => Request ty -> IO (Result (Response ty))
    simpleHTTP (URI -> Request String
    request URI
    uri)
        Maybe String -> IO (Maybe String)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe String -> IO (Maybe String))
    -> Maybe String -> IO (Maybe String)
    forall a b. (a -> b) -> a -> b
    $ case Result (Response String)
    ersp of
          Left ConnError
    _ -> Maybe String
    forall a. Maybe a
    Nothing
          Right Response String
    rsp
            | Response String -> ResponseCode
    forall a. Response a -> ResponseCode
    rspCode Response String
    rsp ResponseCode -> ResponseCode -> Bool
    forall a. Eq a => a -> a -> Bool
    == (Int
    2,Int
    0,Int
    0) -> String -> Maybe String
    forall a. a -> Maybe a
    Just (String -> Maybe String) -> String -> Maybe String
    forall a b. (a -> b) -> a -> b
    $ Response String -> String
    forall a. Response a -> a
    rspBody Response String
    rsp
            | Bool
    otherwise              -> Maybe String
    forall a. Maybe a
    Nothing

    request :: URI -> Request String
    request :: URI -> Request String
    request URI
    uri = Request
      { rqURI :: URI
    rqURI     = URI
    uri
      , rqMethod :: RequestMethod
    rqMethod  = RequestMethod
    GET
      , rqHeaders :: [Header]
    rqHeaders = []
      , rqBody :: String
    rqBody    = String
    ""
      }

    readKeyword :: String -> Keyword
    readKeyword :: String -> Keyword
    readKeyword = String -> Keyword
    forall a. Read a => String -> a
    read (String -> Keyword) -> (String -> String) -> String -> Keyword
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String
    capitalize

    capitalize :: String -> String
    capitalize :: String -> String
    capitalize String
    ""     = String
    ""
    capitalize (Char
    c:String
    cs) = Char -> Char
    toUpper Char
    c Char -> String -> String
    forall a. a -> [a] -> [a]
    : (Char -> Char) -> String -> String
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Char
    toLower String
    cs

    emptyOEIS :: OEISSequence
    emptyOEIS :: OEISSequence
    emptyOEIS = [String]
    -> SequenceData
    -> SequenceData
    -> String
    -> [String]
    -> [String]
    -> [String]
    -> [String]
    -> String
    -> Int
    -> Int
    -> [(Language, String)]
    -> [String]
    -> [String]
    -> [Keyword]
    -> [String]
    -> OEISSequence
    OEIS [] [] [] String
    "" [] [] [] [] String
    "" Int
    0 Int
    0 [] [] [] [] []

    addElement :: (Char, String) -> OEISSequence -> OEISSequence
    addElement :: (Char, String) -> OEISSequence -> OEISSequence
    addElement (Char
    'I', String
    x) OEISSequence
    c = OEISSequence
    c { catalogNums = words x }
    addElement (Char
    t, String
    x)   OEISSequence
    c | Char
    t Char -> String -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` String
    "STU" = OEISSequence
    c { sequenceData = nums ++ sequenceData c }
        where nums :: SequenceData
    nums = (String -> Integer) -> [String] -> SequenceData
    forall a b. (a -> b) -> [a] -> [b]
    map String -> Integer
    forall a. Read a => String -> a
    read ([String] -> SequenceData) -> [String] -> SequenceData
    forall a b. (a -> b) -> a -> b
    $ String -> [String]
    csvItems String
    x
    addElement (Char
    t, String
    x)   OEISSequence
    c | Char
    t Char -> String -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` String
    "VWX" = OEISSequence
    c { signedData = nums ++ signedData c }
        where nums :: SequenceData
    nums = (String -> Integer) -> [String] -> SequenceData
    forall a b. (a -> b) -> [a] -> [b]
    map String -> Integer
    forall a. Read a => String -> a
    read ([String] -> SequenceData) -> [String] -> SequenceData
    forall a b. (a -> b) -> a -> b
    $ String -> [String]
    csvItems String
    x
    addElement (Char
    'N', String
    x) OEISSequence
    c = OEISSequence
    c { description = x                  }
    addElement (Char
    'D', String
    x) OEISSequence
    c = OEISSequence
    c { references  = x : references c }
    addElement (Char
    'H', String
    x) OEISSequence
    c = OEISSequence
    c { links       = x : links c      }
    addElement (Char
    'F', String
    x) OEISSequence
    c = OEISSequence
    c { formulas    = x : formulas c   }
    addElement (Char
    'Y', String
    x) OEISSequence
    c = OEISSequence
    c { xrefs       = x : xrefs c      }
    addElement (Char
    'A', String
    x) OEISSequence
    c = OEISSequence
    c { author      = x                  }
    addElement (Char
    'O', String
    x) OEISSequence
    c = OEISSequence
    c { offset      = read o
                              , firstGT1    = read f }
      where (String
    o,String
    f) = (String -> String) -> (String, String) -> (String, String)
    forall b c d. (b -> c) -> (d, b) -> (d, c)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (d, b) (d, c)
    second String -> String
    forall a. HasCallStack => [a] -> [a]
    tail ((String, String) -> (String, String))
    -> (String -> (String, String)) -> String -> (String, String)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /=Char
    ',') (String -> (String, String)) -> String -> (String, String)
    forall a b. (a -> b) -> a -> b
    $ String
    x
    addElement (Char
    'p', String
    x) OEISSequence
    c = OEISSequence
    c { programs    = (Maple, x) :
                                                programs c     }
    addElement (Char
    't', String
    x) OEISSequence
    c = OEISSequence
    c { programs    = (Mathematica, x) :
                                                programs c     }
    addElement (Char
    'o', String
    x) OEISSequence
    c = OEISSequence
    c { programs    = (Other, x) :
                                                programs c     }
    addElement (Char
    'E', String
    x) OEISSequence
    c = OEISSequence
    c { extensions  = x : extensions c }
    addElement (Char
    'e', String
    x) OEISSequence
    c = OEISSequence
    c { examples    = x : examples c   }
    addElement (Char
    'K', String
    x) OEISSequence
    c = OEISSequence
    c { keywords    = parseKeywords x    }
    addElement (Char
    'C', String
    x) OEISSequence
    c = OEISSequence
    c { comments    = x : comments c   }
    addElement (Char, String)
    _ OEISSequence
    c = OEISSequence
    c

    parseOEIS :: String -> [OEISSequence]
    parseOEIS :: String -> [OEISSequence]
    parseOEIS String
    x = if String
    "No results." String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` ([String]
    ls[String] -> Int -> String
    forall a. HasCallStack => [a] -> Int -> a
    !!Int
    3)
                    then []
                    else [(Char, String)] -> [OEISSequence]
    go ([(Char, String)] -> [OEISSequence])
    -> ([String] -> [(Char, String)]) -> [String] -> [OEISSequence]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((Char, String) -> Bool) -> [(Char, String)] -> [(Char, String)]
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhile ((Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Char
    'I') (Char -> Bool)
    -> ((Char, String) -> Char) -> (Char, String) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char, String) -> Char
    forall a b. (a, b) -> a
    fst) ([(Char, String)] -> [(Char, String)])
    -> ([String] -> [(Char, String)]) -> [String] -> [(Char, String)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [String] -> [(Char, String)]
    parseRawOEIS ([String] -> [OEISSequence]) -> [String] -> [OEISSequence]
    forall a b. (a -> b) -> a -> b
    $ [String]
    ls'
        where ls :: [String]
    ls = String -> [String]
    lines String
    x
              ls' :: [String]
    ls' = [String] -> [String]
    forall a. HasCallStack => [a] -> [a]
    init ([String] -> [String])
    -> ([String] -> [String]) -> [String] -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [String] -> [String]
    forall a. Int -> [a] -> [a]
    drop Int
    5 ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ [String]
    ls
              go :: [(Char, String)] -> [OEISSequence]
    go [] = []
              go ((Char, String)
    i:[(Char, String)]
    xs) = (OEISSequence -> (Char, String) -> OEISSequence)
    -> OEISSequence -> [(Char, String)] -> OEISSequence
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (((Char, String) -> OEISSequence -> OEISSequence)
    -> OEISSequence -> (Char, String) -> OEISSequence
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (Char, String) -> OEISSequence -> OEISSequence
    addElement) OEISSequence
    emptyOEIS ([(Char, String)] -> [(Char, String)]
    forall a. [a] -> [a]
    reverse ((Char, String)
    i(Char, String) -> [(Char, String)] -> [(Char, String)]
    forall a. a -> [a] -> [a]
    :[(Char, String)]
    ys)) OEISSequence -> [OEISSequence] -> [OEISSequence]
    forall a. a -> [a] -> [a]
    : [(Char, String)] -> [OEISSequence]
    go [(Char, String)]
    zs
                  where ([(Char, String)]
    ys, [(Char, String)]
    zs) = ((Char, String) -> Bool)
    -> [(Char, String)] -> ([(Char, String)], [(Char, String)])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break ((Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    'I') (Char -> Bool)
    -> ((Char, String) -> Char) -> (Char, String) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char, String) -> Char
    forall a b. (a, b) -> a
    fst) [(Char, String)]
    xs

    parseRawOEIS :: [String] -> [(Char, String)]
    parseRawOEIS :: [String] -> [(Char, String)]
    parseRawOEIS = (String -> (Char, String)) -> [String] -> [(Char, String)]
    forall a b. (a -> b) -> [a] -> [b]
    map String -> (Char, String)
    parseItem ([String] -> [(Char, String)])
    -> ([String] -> [String]) -> [String] -> [(Char, String)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [String] -> [String]
    combineConts

    parseKeywords :: String -> [Keyword]
    parseKeywords :: String -> [Keyword]
    parseKeywords = (String -> Keyword) -> [String] -> [Keyword]
    forall a b. (a -> b) -> [a] -> [b]
    map String -> Keyword
    readKeyword ([String] -> [Keyword])
    -> (String -> [String]) -> String -> [Keyword]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    csvItems

    csvItems :: String -> [String]
    csvItems :: String -> [String]
    csvItems String
    "" = []
    csvItems String
    x = String
    item String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : [String]
    others
        where (String
    item, String
    rest) = (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    span (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /=Char
    ',') String
    x
              others :: [String]
    others = String -> [String]
    csvItems (String -> [String]) -> String -> [String]
    forall a b. (a -> b) -> a -> b
    $ Char -> String -> String
    del Char
    ',' String
    rest

    del :: Char -> String -> String
    del :: Char -> String -> String
    del Char
    _ String
    ""     = String
    ""
    del Char
    c (Char
    x:String
    xs) | Char
    cChar -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    ==Char
    x      = String
    xs
                 | Bool
    otherwise = Char
    xChar -> String -> String
    forall a. a -> [a] -> [a]
    :String
    xs

    parseItem :: String -> (Char, String)
    parseItem :: String -> (Char, String)
    parseItem String
    s = (Char
    c, String
    str)
        where ( Char
    '%':Char
    c:String
    _ , String
    rest) = String -> (String, String)
    splitWord String
    s
              (String
    _, String
    str )    = if Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    'I' then (String
    "", String
    rest)
                                         else String -> (String, String)
    splitWord String
    rest

    combineConts :: [String] -> [String]
    combineConts :: [String] -> [String]
    combineConts (s :: String
    s@(Char
    '%':Char
    _:String
    _) : [String]
    ss) =
      (String -> [String] -> [String]) -> (String, [String]) -> [String]
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry (:) ((String, [String]) -> [String])
    -> ([String] -> (String, [String])) -> [String] -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> [String] -> String
    joinConts String
    s ([String] -> String)
    -> ([String] -> [String])
    -> ([String], [String])
    -> (String, [String])
    forall b c b' c'. (b -> c) -> (b' -> c') -> (b, b') -> (c, c')
    forall (a :: * -> * -> *) b c b' c'.
    Arrow a =>
    a b c -> a b' c' -> a (b, b') (c, c')
    *** [String] -> [String]
    combineConts) (([String], [String]) -> (String, [String]))
    -> ([String] -> ([String], [String]))
    -> [String]
    -> (String, [String])
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> Bool) -> [String] -> ([String], [String])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break String -> Bool
    isItem ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ [String]
    ss
    combineConts [String]
    ss = [String]
    ss

    splitWord :: String -> (String, String)
    splitWord :: String -> (String, String)
    splitWord = (String -> String) -> (String, String) -> (String, String)
    forall b c d. (b -> c) -> (d, b) -> (d, c)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (d, b) (d, c)
    second String -> String
    trimLeft ((String, String) -> (String, String))
    -> (String -> (String, String)) -> String -> (String, String)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break Char -> Bool
    isSpace

    isItem :: String -> Bool
    isItem :: String -> Bool
    isItem String
    x = Bool -> Bool
    not (String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    x) Bool -> Bool -> Bool
    && Char
    '%' Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == String -> Char
    forall a. HasCallStack => [a] -> a
    head String
    x

    joinConts :: String -> [String] -> String
    joinConts :: String -> [String] -> String
    joinConts String
    s [String]
    conts = String
    s String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ (String -> String) -> [String] -> String
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap String -> String
    trimLeft [String]
    conts

    trimLeft :: String -> String
    trimLeft :: String -> String
    trimLeft = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhile Char -> Bool
    isSpace