{-# LANGUAGE FlexibleContexts #-}

module DataAnalysis04 where

import Data.Convertible (Convertible)
import Data.List (genericIndex, genericLength, genericTake)
import Database.HDBC (SqlValue, disconnect, fromSql, quickQuery')
import Database.HDBC.Sqlite3 (connectSqlite3)

import DataAnalysis02 (average)

readSqlColumn :: Convertible SqlValue a => [[SqlValue]] -> Integer -> [a]
readSqlColumn sqlResult index = map (fromSql . (`genericIndex` index)) sqlResult

queryDatabase :: FilePath -> String -> IO [[SqlValue]]
queryDatabase databaseFile sqlQuery = do
  conn <- connectSqlite3 databaseFile
  result <- quickQuery' conn sqlQuery []
  disconnect conn
  return result

pullStockClosingPrices :: FilePath -> String -> IO [(Double, Double)]
pullStockClosingPrices databaseFile database = do
  sqlResult <- queryDatabase databaseFile
                             ("SELECT rowid, adjclose FROM " ++ database)
  return $ zip (reverse $ readSqlColumn sqlResult 0)
               (readSqlColumn sqlResult 1)

percentChange :: Double -> Double -> Double
percentChange value first = 100 * (value - first) / first

applyPercentChangeToData :: [(Double, Double)] -> [(Double, Double)]
applyPercentChangeToData dataset = zip indices scaledData
  where (_, first) = last dataset
        indices = reverse [1.0 .. genericLength dataset]
        scaledData = map (\(_, value) -> percentChange value first) dataset

movingAverage :: [Double] -> Integer -> [Double]
movingAverage values window
  | window >= genericLength values = [average values]
  | otherwise =
      average (genericTake window values) : movingAverage (tail values) window

applyMovingAverageToData :: [(Double, Double)] -> Integer -> [(Double, Double)]
applyMovingAverageToData dataset window =
  zip [fromIntegral window..] (movingAverage (map snd (reverse dataset)) window)

pullLatitudeLongitude :: FilePath -> String -> IO [(Double, Double)]
pullLatitudeLongitude databaseFile database = do
  sqlResult <- queryDatabase databaseFile
                             ("SELECT latitude, longitude FROM " ++ database)
  return $ zip (readSqlColumn sqlResult 1) (readSqlColumn sqlResult 0)
