module Elm.Encoder
    ( encoder
    ) where

import           Elm.Types
import           Elm.Helpers

elmEncoder :: Expr -> String
elmEncoder (Primitive t) = case t of
    Bool ->
        "Json.Encode.bool"
    String ->
        "Json.Encode.string"
    Float ->
        "Json.Encode.float"
    Int ->
        "Json.Encode.int"
    p -> error $ "No encoder for Primitive known: " ++ show p
elmEncoder (Field f) = elmEncoder f
elmEncoder (DataType name _) = "encode" ++ name
elmEncoder (Product (Primitive List) (Primitive Char)) = elmEncoder $ Primitive String
elmEncoder (Product (Primitive List) t) =
    concat $ surround "(" " << " ")"
        [ "Json.Encode.list"
        , "List.map " ++ elmEncoder t
        ]
elmEncoder (Product (Primitive Maybe) t) =
    concat $ surround "(" " << " ")"
        [ "Maybe.withDefault Json.Encode.null"
        , "Maybe.map " ++ elmEncoder t
        ]
elmEncoder d = error $ "No encoder for definition known: " ++ show d

encoder :: Expr -> String
encoder (DataType name (Record _ expr)) = format
    [ func ++ " : " ++ name ++ " -> Json.Encode.Value"
    , func ++ " o ="
    , tab 4 "Json.Encode.object"
    , format $ map (tab 8) $ surround "[ " ", " "]" $ build expr
    ]
    where func = "encode" ++ name
          build (Product s1 s2) = build s1 ++ build s2
          build (Selector recordSel jsonSel t) =
              [ concat $ surround "(" ", " ")"
                  [ show jsonSel
                  , (elmEncoder t) ++ " o." ++ recordSel
                  ]
              ]
          build d = error $ "Unsupported Record encoder Selector definition: " ++ show d
encoder d = error $ "Unsupported encoder definition: " ++ show d