{-# 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 (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 (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 SeqData
getSeqData = IO (Maybe SeqData) -> Maybe SeqData
forall a. IO a -> a
unsafePerformIO (IO (Maybe SeqData) -> Maybe SeqData)
-> (SearchStatus -> IO (Maybe SeqData))
-> SearchStatus
-> Maybe SeqData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SearchStatus -> IO (Maybe SeqData)
getSeqData'

-- | getSeqData in IO
getSeqData' :: SearchStatus -> IO (Maybe SeqData)
getSeqData' :: SearchStatus -> IO (Maybe SeqData)
getSeqData' = ((OEISSeq -> SeqData
seqData (OEISSeq -> SeqData) -> Maybe OEISSeq -> Maybe SeqData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe OEISSeq -> Maybe SeqData)
-> IO (Maybe OEISSeq) -> IO (Maybe SeqData)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (IO (Maybe OEISSeq) -> IO (Maybe SeqData))
-> (SearchStatus -> IO (Maybe OEISSeq))
-> SearchStatus
-> IO (Maybe SeqData)
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 :: SeqData -> SeqData
extendSeq = IO SeqData -> SeqData
forall a. IO a -> a
unsafePerformIO (IO SeqData -> SeqData)
-> (SeqData -> IO SeqData) -> SeqData -> SeqData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SeqData -> IO SeqData
extendSeq'

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