{-# LANGUAGE GADTs               #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Database.DSH.CSV (csvImport) where

import Database.DSH.Internals

import qualified Data.Text as T
import Text.CSV

csvImport :: (Reify a) => FilePath -> Type [a] -> IO (Exp [a])
csvImport filepath csvType = do
  let rType = recordType csvType
  contents <- readFile filepath
  let csv1 = case parseCSV filepath contents of
               Left er -> error (show er)
               Right r -> filter (\l -> not (all null l) || length l > 1) (tail r)
  return (ListE (fmap (csvRecordToNorm rType) csv1))
  where csvError :: String -> a
        csvError s = error ("Error in '" ++ filepath ++ "': " ++ s)

        recordType :: Type [a] -> Type a
        recordType (ListT rType) = rType

        csvRecordToNorm :: Type a -> [String] -> Exp a
        csvRecordToNorm UnitT  [] = UnitE
        csvRecordToNorm t      [] = csvError ("When converting record '" ++ "[]" ++ "' to a value of type '" ++ show t ++ "'")
        csvRecordToNorm t1     [bs] = csvFieldToNorm t1 bs
        csvRecordToNorm (PairT (t1 :: Type b) (t2 :: Type c)) (bs : bss) = PairE (csvFieldToNorm t1 bs :: Exp b) (csvRecordToNorm t2 bss)
        csvRecordToNorm t           rs       = csvError ("When converting record '" ++ show rs ++ "' to a value of type '" ++ show t ++ "'")


        csvFieldToNorm :: Type a -> String -> Exp a
        csvFieldToNorm t s = case t of
          UnitT      -> UnitE
          BoolT      -> BoolE    (read s) 
          CharT      -> CharE    (head s) 
          IntegerT   -> IntegerE (read s) 
          DoubleT    -> DoubleE  (read s) 
          TextT      -> TextE    (T.pack s) 
          _          -> er
          where er = csvError ("When converting CSV field'" ++ s ++ "' to a value of type '" ++ show t ++ "'")