content: -- | Module for getting stock prices.
  module B1.Data.Price
    ( Price (..)
    , getPriceChange
    , getWeeklyPrices
    ) where
  
  import Data.List
  import Data.Time
  import Data.Time.Calendar.WeekDate
  
  -- | Price information during some time interval.
  data Price = Price
    { startTime :: LocalTime -- ^ Start time of the trading period
    , endTime :: LocalTime -- ^ End time of the trading period
    , open :: Float -- ^ Opening price of the trading period
    , high :: Float -- ^ Highest price during the trading period
    , low :: Float -- ^ Lowest price during the trading period
    , close :: Float -- ^ Closing price of the trading period.
    , volume :: Int -- ^ Volume of the trading period.
    } deriving (Show, Eq)
  
  getPriceChange :: [Price] -> Int -> Float
  getPriceChange prices index 
    | index + 1 < length prices = change
    | otherwise = 0
    where
      currClose = close $ prices !! index
      prevClose = close $ prices !! (index + 1)
      change = currClose - prevClose
  
  getWeeklyPrices :: [Price] -> [Price]
  getWeeklyPrices dailyPrices =
    map flattenWeeklyPriceGroup $ getWeeklyPriceGroups dailyPrices
  
  getWeeklyPriceGroups :: [Price] -> [[Price]]
  getWeeklyPriceGroups dailyPrices =
    groupBy sameWeekNumber dailyPrices
  
  sameWeekNumber :: Price -> Price -> Bool
  sameWeekNumber price otherPrice =
    let week = getWeekNumber price
        otherWeek = getWeekNumber otherPrice
    in week == otherWeek
  
  getWeekNumber :: Price -> Int
  getWeekNumber price = weekNumber
    where
      day = localDay $ endTime price
      (_, weekNumber, _) = toWeekDate day
  
  flattenWeeklyPriceGroup :: [Price] -> Price
  flattenWeeklyPriceGroup prices =
    Price
      { startTime = flatStartTime
      , endTime = flatEndTime
      , open = flatOpen
      , high = flatHigh
      , low = flatLow
      , close = flatClose
      , volume = flatVolume
      }
    where
      flatStartTime = startTime $ last prices
      flatEndTime = endTime $ head prices
      flatOpen = open $ last prices
      flatHigh = maximum $ map high prices
      flatLow = minimum $ map low prices
      flatClose = close $ head prices
      flatVolume = sum $ map volume prices
  
  