module Web.Data.Yahoo.Request where

import Data.List (intercalate)
import Data.Maybe (catMaybes)
import Data.Time.Calendar (Day, fromGregorian)
import Text.Printf (printf)

import Web.Data.Yahoo.Utils (dayAsEpoch)

data Ticker = Ticker String

class YahooParam a where
    key    :: a -> String
    symbol :: a -> String

paramToString :: YahooParam a => a -> String
paramToString :: forall a. YahooParam a => a -> [Char]
paramToString a
p = forall r. PrintfType r => [Char] -> r
printf [Char]
"%s=%s" (forall a. YahooParam a => a -> [Char]
key a
p) (forall a. YahooParam a => a -> [Char]
symbol a
p)

data Interval = 
    Daily
    | Weekly
    | Monthly
    deriving (Int -> Interval -> [Char] -> [Char]
[Interval] -> [Char] -> [Char]
Interval -> [Char]
forall a.
(Int -> a -> [Char] -> [Char])
-> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
showList :: [Interval] -> [Char] -> [Char]
$cshowList :: [Interval] -> [Char] -> [Char]
show :: Interval -> [Char]
$cshow :: Interval -> [Char]
showsPrec :: Int -> Interval -> [Char] -> [Char]
$cshowsPrec :: Int -> Interval -> [Char] -> [Char]
Show, Interval -> Interval -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Interval -> Interval -> Bool
$c/= :: Interval -> Interval -> Bool
== :: Interval -> Interval -> Bool
$c== :: Interval -> Interval -> Bool
Eq)

instance YahooParam Interval where
    key :: Interval -> [Char]
key Interval
_ = [Char]
"interval"
    symbol :: Interval -> [Char]
symbol Interval
Daily = [Char]
"1d"
    symbol Interval
Weekly = [Char]
"1wk"
    symbol Interval
Monthly = [Char]
"1mo"

data Events =
    HistoricalPrices
    | Dividends
    | Splits

instance YahooParam Events where
    key :: Events -> [Char]
key Events
_ = [Char]
"events"
    symbol :: Events -> [Char]
symbol Events
HistoricalPrices = [Char]
"history"
    symbol Events
Dividends = [Char]
"div"
    symbol Events
Splits = [Char]
"split"

data FromEndpoint = FromEndpoint Day

instance YahooParam FromEndpoint where
    key :: FromEndpoint -> [Char]
key FromEndpoint
_ = [Char]
"period1"
    symbol :: FromEndpoint -> [Char]
symbol (FromEndpoint Day
day) = forall a. Show a => a -> [Char]
show forall a b. (a -> b) -> a -> b
$ Day -> Integer
dayAsEpoch Day
day

data ToEndpoint = ToEndpoint Day

instance YahooParam ToEndpoint where
    key :: ToEndpoint -> [Char]
key ToEndpoint
_ = [Char]
"period2"
    symbol :: ToEndpoint -> [Char]
symbol (ToEndpoint Day
day) = forall a. Show a => a -> [Char]
show forall a b. (a -> b) -> a -> b
$ Day -> Integer
dayAsEpoch Day
day

data TimeRange =
    After Day
    | Before Day
    | Range Day Day

timeRangeToEndpoints :: TimeRange -> (FromEndpoint, ToEndpoint)
timeRangeToEndpoints :: TimeRange -> (FromEndpoint, ToEndpoint)
timeRangeToEndpoints (After Day
day)     = (Day -> FromEndpoint
FromEndpoint Day
day, Day -> ToEndpoint
ToEndpoint forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromGregorian Integer
2050 Int
12 Int
31)
timeRangeToEndpoints (Before Day
day)    = (Day -> FromEndpoint
FromEndpoint forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromGregorian Integer
1970 Int
1 Int
1, Day -> ToEndpoint
ToEndpoint Day
day)
timeRangeToEndpoints (Range Day
from Day
to) = (Day -> FromEndpoint
FromEndpoint Day
from, Day -> ToEndpoint
ToEndpoint Day
to)

data YahooRequest = YahooRequest {
    YahooRequest -> Ticker
ticker   :: Ticker,
    YahooRequest -> Maybe Interval
interval :: Maybe Interval,
    YahooRequest -> Maybe TimeRange
period   :: Maybe TimeRange
}

requestUrl :: YahooRequest -> String
requestUrl :: YahooRequest -> [Char]
requestUrl (YahooRequest { ticker :: YahooRequest -> Ticker
ticker = (Ticker [Char]
t), interval :: YahooRequest -> Maybe Interval
interval = Maybe Interval
i, period :: YahooRequest -> Maybe TimeRange
period = Maybe TimeRange
p }) = 
    forall r. PrintfType r => [Char] -> r
printf [Char]
"%s/%s%s" [Char]
baseUrl [Char]
t ([[Char]] -> [Char]
queryString [[Char]]
queryParams)
    where
        baseUrl :: String
        baseUrl :: [Char]
baseUrl = [Char]
"http://query1.finance.yahoo.com/v7/finance/download"

        rangeEndpoints :: Maybe (FromEndpoint, ToEndpoint)
        rangeEndpoints :: Maybe (FromEndpoint, ToEndpoint)
rangeEndpoints = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TimeRange -> (FromEndpoint, ToEndpoint)
timeRangeToEndpoints Maybe TimeRange
p

        fromEndpoint :: Maybe FromEndpoint
        fromEndpoint :: Maybe FromEndpoint
fromEndpoint = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst Maybe (FromEndpoint, ToEndpoint)
rangeEndpoints

        toEndpoint :: Maybe ToEndpoint
        toEndpoint :: Maybe ToEndpoint
toEndpoint = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd Maybe (FromEndpoint, ToEndpoint)
rangeEndpoints

        queryParams :: [String]
        queryParams :: [[Char]]
queryParams = forall a. [Maybe a] -> [a]
catMaybes forall a b. (a -> b) -> a -> b
$ [
                forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. YahooParam a => a -> [Char]
paramToString Maybe Interval
i,
                forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. YahooParam a => a -> [Char]
paramToString Maybe FromEndpoint
fromEndpoint,
                forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. YahooParam a => a -> [Char]
paramToString Maybe ToEndpoint
toEndpoint
            ]

        queryString :: [String] -> String
        queryString :: [[Char]] -> [Char]
queryString [] = [Char]
""
        queryString [[Char]]
ps = forall r. PrintfType r => [Char] -> r
printf [Char]
"?%s" (forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"&" [[Char]]
ps)