{-# LANGUAGE OverloadedLists #-}

module Math.OEIS (
  -- * Functions
  searchSeq,  searchSeq',
  lookupSeq,  lookupSeq',
  getSeqData, getSeqData',
  extendSeq,  extendSeq',

  -- * Types
  SeqData,
  SearchStatus(..),
  Keyword(..),
  OEISSeq(..)
  ) where

import           Data.Functor
import           Data.List
import           Data.Maybe         (fromMaybe, listToMaybe)
import qualified Data.Vector        as V
import           System.IO.Unsafe   (unsafePerformIO)

import           Math.OEIS.Internal
import           Math.OEIS.Types


-- | Get all search results on OEIS
--
-- e.g.
--
-- > ghci>searchSeq (ID "A000027") 0
-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...
--
-- > ghci>searchSeq (SubSeq [1,2,3,4]) 0
-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...
-- > ghci>length it
-- > 53
-- > ghci>searchSeq (SubSeq [1,2,3,4]) 17
-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,8,9,
-- > ghci>length it
-- > 17
--
-- > ghci>searchSeq (SubSeq [1,1,4,5,1,4,1,9,1,9,8,9,3]) 0
-- > []
searchSeq :: SearchStatus -> Int -> V.Vector OEISSeq
searchSeq :: SearchStatus -> Int -> Vector OEISSeq
searchSeq SearchStatus
ss = IO (Vector OEISSeq) -> Vector OEISSeq
forall a. IO a -> a
unsafePerformIO (IO (Vector OEISSeq) -> Vector OEISSeq)
-> (Int -> IO (Vector OEISSeq)) -> Int -> Vector OEISSeq
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SearchStatus -> Int -> IO (Vector OEISSeq)
searchSeq' SearchStatus
ss

-- | searchSeq in IO
searchSeq' :: SearchStatus -> Int -> IO (V.Vector OEISSeq)
searchSeq' :: SearchStatus -> Int -> IO (Vector OEISSeq)
searchSeq' SearchStatus
ss Int
bound = do
  Vector Value
results' <- SearchStatus -> Int -> Int -> Vector Value -> IO (Vector Value)
getResults SearchStatus
ss Int
0 Int
bound []
  let seqs :: Vector OEISSeq
seqs
        | Vector Value -> Bool
forall a. Vector a -> Bool
V.null Vector Value
results' = []
        | Bool
otherwise       = Value -> OEISSeq
parseOEIS (Value -> OEISSeq) -> Vector Value -> Vector OEISSeq
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Vector Value
results'
  Vector OEISSeq -> IO (Vector OEISSeq)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Vector OEISSeq
seqs


-- | Look up a sequence on OEIS.
--
-- e.g.
--
-- > ghci>lookupSeq (ID "A000027")
-- > Just (OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...
--
-- > ghci>lookupSeq (SubSeq [1,2,3,4])
-- > Just (OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...
lookupSeq :: SearchStatus -> Maybe OEISSeq
lookupSeq :: SearchStatus -> Maybe OEISSeq
lookupSeq = IO (Maybe OEISSeq) -> Maybe OEISSeq
forall a. IO a -> a
unsafePerformIO (IO (Maybe OEISSeq) -> Maybe OEISSeq)
-> (SearchStatus -> IO (Maybe OEISSeq))
-> SearchStatus
-> Maybe OEISSeq
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SearchStatus -> IO (Maybe OEISSeq)
lookupSeq'

-- | lookupSeq in IO
lookupSeq' :: SearchStatus -> IO (Maybe OEISSeq)
lookupSeq' :: SearchStatus -> IO (Maybe OEISSeq)
lookupSeq' SearchStatus
ss = do
  Maybe Value
result <- SearchStatus -> Int -> IO (Maybe Value)
getResult SearchStatus
ss Int
0
  Maybe OEISSeq -> IO (Maybe OEISSeq)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe OEISSeq -> IO (Maybe OEISSeq))
-> Maybe OEISSeq -> IO (Maybe OEISSeq)
forall a b. (a -> b) -> a -> b
$ case Maybe Value
result of
             Just Value
result' -> OEISSeq -> Maybe OEISSeq
forall a. a -> Maybe a
Just (OEISSeq -> Maybe OEISSeq) -> OEISSeq -> Maybe OEISSeq
forall a b. (a -> b) -> a -> b
$ Value -> OEISSeq
parseOEIS Value
result'
             Maybe Value
_            -> Maybe OEISSeq
forall a. Maybe a
Nothing


-- | Get sub-sequence on OEIS.
--
-- e.g.
--
-- > ghci>getSeqData (ID "A000027")
-- > Just [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]
--
-- > ghci>getSeqData (SubSeq [1,2,3,4])
-- > Just [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]
--
getSeqData :: SearchStatus -> Maybe SeqData
getSeqData :: SearchStatus -> Maybe [Integer]
getSeqData = IO (Maybe [Integer]) -> Maybe [Integer]
forall a. IO a -> a
unsafePerformIO (IO (Maybe [Integer]) -> Maybe [Integer])
-> (SearchStatus -> IO (Maybe [Integer]))
-> SearchStatus
-> Maybe [Integer]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SearchStatus -> IO (Maybe [Integer])
getSeqData'

-- | getSeqData in IO
getSeqData' :: SearchStatus -> IO (Maybe SeqData)
getSeqData' :: SearchStatus -> IO (Maybe [Integer])
getSeqData' = ((OEISSeq -> [Integer]
seqData (OEISSeq -> [Integer]) -> Maybe OEISSeq -> Maybe [Integer]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe OEISSeq -> Maybe [Integer])
-> IO (Maybe OEISSeq) -> IO (Maybe [Integer])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (IO (Maybe OEISSeq) -> IO (Maybe [Integer]))
-> (SearchStatus -> IO (Maybe OEISSeq))
-> SearchStatus
-> IO (Maybe [Integer])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SearchStatus -> IO (Maybe OEISSeq)
lookupSeq'


-- | Extend from sub-sequence.
--
-- e.g.
--
-- > ghci>extendSeq [1,2,3,4]
-- > [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]
--
-- > ghci> extendSeq [1,3,2,5,6,1,6]
-- > [1,3,2,5,6,1,6]
extendSeq :: SeqData -> SeqData
extendSeq :: [Integer] -> [Integer]
extendSeq = IO [Integer] -> [Integer]
forall a. IO a -> a
unsafePerformIO (IO [Integer] -> [Integer])
-> ([Integer] -> IO [Integer]) -> [Integer] -> [Integer]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Integer] -> IO [Integer]
extendSeq'

-- | extendSeq in IO
extendSeq' :: [Integer] -> IO [Integer]
extendSeq' :: [Integer] -> IO [Integer]
extendSeq' [] = [Integer] -> IO [Integer]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
extendSeq' [Integer]
sd = do
  Maybe OEISSeq
oeis <- SearchStatus -> IO (Maybe OEISSeq)
lookupSeq' ([Integer] -> SearchStatus
SubSeq [Integer]
sd)
  [Integer] -> IO [Integer]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Integer] -> IO [Integer]) -> [Integer] -> IO [Integer]
forall a b. (a -> b) -> a -> b
$ case Maybe OEISSeq
oeis of
    Just OEISSeq
s -> [Integer] -> [Integer] -> [Integer]
extend [Integer]
sd (OEISSeq -> [Integer]
seqData OEISSeq
s)
    Maybe OEISSeq
_      -> [Integer]
sd
  where
    extend :: SeqData -> SeqData -> SeqData
    extend :: [Integer] -> [Integer] -> [Integer]
extend [Integer]
sd [Integer]
ext = [Integer] -> Maybe [Integer] -> [Integer]
forall a. a -> Maybe a -> a
fromMaybe [Integer]
sd (Maybe [Integer] -> [Integer])
-> ([[Integer]] -> Maybe [Integer]) -> [[Integer]] -> [Integer]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Integer] -> Bool) -> [[Integer]] -> Maybe [Integer]
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ([Integer]
sd [Integer] -> [Integer] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) ([[Integer]] -> [Integer]) -> [[Integer]] -> [Integer]
forall a b. (a -> b) -> a -> b
$ [Integer] -> [[Integer]]
forall a. [a] -> [[a]]
tails [Integer]
ext