{-|
This module contains the definition of `Symbol`, `SymbolMap`, and helper functions.
-}
module Lsql.Csv.Core.Symbols
  (
    Symbol, SymbolMap, (-->), (==>),
    getSymbolMap, symbolList,
    getTables
  )
where

import Lsql.Csv.Core.Tables
import qualified Data.Map as M
import Data.List

-- | The datatype for a single named column (Symbol)
data Symbol = NamedColumn 
  String -- ^ identifier of column 
  Column -- ^ column itself
  String -- ^ name alias of column

-- | The datatype containing a `M.Map` for aliases of `Symbol`s and a list of all `Table`s
data SymbolMap = SymbolMap (M.Map String Symbol) [Table]

emptySymbolMap :: [Table] -> SymbolMap
emptySymbolMap :: [Table] -> SymbolMap
emptySymbolMap [Table]
tables = Map String Symbol -> [Table] -> SymbolMap
SymbolMap Map String Symbol
forall k a. Map k a
M.empty [Table]
tables

getSymbolName :: Symbol -> String
getSymbolName :: Symbol -> String
getSymbolName (NamedColumn String
_ Column
_ String
name) = String
name

-- | Returns the list of name aliases of all columns.
symbolList :: SymbolMap -> [String]
symbolList :: SymbolMap -> [String]
symbolList (SymbolMap Map String Symbol
t_map [Table]
_) = ((String, Symbol) -> String) -> [(String, Symbol)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((String, Symbol) -> String
forall a b. (a, b) -> a
fst) (Map String Symbol -> [(String, Symbol)]
forall k a. Map k a -> [(k, a)]
M.toList Map String Symbol
t_map)

(+++) :: SymbolMap -> [Symbol] -> SymbolMap
(SymbolMap Map String Symbol
s_map [Table]
tables) +++ :: SymbolMap -> [Symbol] -> SymbolMap
+++ [] = Map String Symbol -> [Table] -> SymbolMap
SymbolMap Map String Symbol
s_map [Table]
tables
(SymbolMap Map String Symbol
s_map [Table]
tables) +++ (Symbol
a : [Symbol]
s_array) =  
  let name :: String
name = Symbol -> String
getSymbolName Symbol
a in
  (Map String Symbol -> [Table] -> SymbolMap
SymbolMap (String -> Symbol -> Map String Symbol -> Map String Symbol
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert String
name Symbol
a Map String Symbol
s_map) [Table]
tables) SymbolMap -> [Symbol] -> SymbolMap
+++ [Symbol]
s_array

-- | Lookup for a `Symbol` (NamedColumn) in a `SymbolMap`
(-->) :: SymbolMap -> String -> Symbol
(SymbolMap Map String Symbol
s_map [Table]
_) --> :: SymbolMap -> String -> Symbol
--> String
name = 
  case String -> Map String Symbol -> Maybe Symbol
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
name Map String Symbol
s_map of
    Maybe Symbol
Nothing -> String -> Symbol
forall a. HasCallStack => String -> a
error(String -> Symbol) -> String -> Symbol
forall a b. (a -> b) -> a -> b
$ String
"Symbol " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" not found. " 
    Just Symbol
s -> Symbol
s

-- | Lookup for a `Symbol` (NamedColumn) in a `SymbolMap`
-- returning a `Column`
(==>) :: SymbolMap -> String -> Column
SymbolMap
s_map ==> :: SymbolMap -> String -> Column
==> String
name =
  let (NamedColumn String
_ Column
ret String
_) = SymbolMap
s_map SymbolMap -> String -> Symbol
--> String
name in
  Column
ret

getSymbolsFromTable :: Table -> [Symbol]
getSymbolsFromTable :: Table -> [Symbol]
getSymbolsFromTable Table
table = 
  let c_names :: [([String], Column)]
c_names = Table -> [([String], Column)]
columnNames Table
table in
  [String -> Column -> String -> Symbol
NamedColumn ([String] -> String
forall a. HasCallStack => [a] -> a
head [String]
names) Column
col String
name | ([String]
names, Column
col) <- [([String], Column)]
c_names, String
name <- [String]
names]

-- | Generates a `SymbolMap` out of a list of `Table`.
getSymbolMap :: [Table] -> SymbolMap
getSymbolMap :: [Table] -> SymbolMap
getSymbolMap [Table]
tables =
  (SymbolMap -> [Symbol] -> SymbolMap)
-> SymbolMap -> [[Symbol]] -> SymbolMap
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl SymbolMap -> [Symbol] -> SymbolMap
(+++) ([Table] -> SymbolMap
emptySymbolMap [Table]
tables)([[Symbol]] -> SymbolMap) -> [[Symbol]] -> SymbolMap
forall a b. (a -> b) -> a -> b
$ 
    (Table -> [Symbol]) -> [Table] -> [[Symbol]]
forall a b. (a -> b) -> [a] -> [b]
map Table -> [Symbol]
getSymbolsFromTable [Table]
tables


-- | Returns the list of `Table`s out of `SymbolMap`.
getTables :: SymbolMap -> [Table]
getTables :: SymbolMap -> [Table]
getTables (SymbolMap Map String Symbol
_ [Table]
tables) = [Table]
tables