content: {-# LANGUAGE OverloadedStrings #-}
  
  module Elm.Encoder
    ( toElmEncoderRef
    , toElmEncoderRefWith
    , toElmEncoderSource
    , toElmEncoderSourceWith
    ) where
  
  import Control.Monad.Reader
  import Data.Monoid
  import qualified Data.Text as T
  import Elm.Common
  import Elm.Type
  import Text.PrettyPrint.Leijen.Text hiding ((<$>), (<>))
  
  class HasEncoder a where
    render :: a -> Reader Options Doc
  
  class HasEncoderRef a where
    renderRef :: a -> Reader Options Doc
  
  instance HasEncoder ElmDatatype where
    render d@(ElmDatatype name constructor) = do
      fnName <- renderRef d
      ctor <- render constructor
      return $
        (fnName <+> ":" <+> stext name <+> "->" <+> "Json.Encode.Value") <$$>
        (fnName <+> "x =" <$$> indent 4 ctor)
    render (ElmPrimitive primitive) = renderRef primitive
  
  instance HasEncoderRef ElmDatatype where
    renderRef (ElmDatatype name _) = pure $ "encode" <> stext name
    renderRef (ElmPrimitive primitive) = renderRef primitive
  
  instance HasEncoder ElmConstructor where
    render (RecordConstructor _ value) = do
      dv <- render value
      return . nest 4 $ "Json.Encode.object" <$$> "[" <+> dv <$$> "]"
  
  instance HasEncoder ElmValue where
    render (ElmField name value) = do
      fieldModifier <- asks fieldLabelModifier
      valueBody <- render value
      return . spaceparens $
        dquotes (stext (fieldModifier name)) <> comma <+>
        (valueBody <+> "x." <> stext name)
    render (ElmPrimitiveRef primitive) = renderRef primitive
    render (ElmRef name) = pure $ "encode" <> stext name
    render (Values x y) = do
      dx <- render x
      dy <- render y
      return $ dx <$$> comma <+> dy
  
  instance HasEncoderRef ElmPrimitive where
    renderRef EDate = pure $ parens "Json.Encode.string << toString"
    renderRef EUnit = pure "Json.Encode.null"
    renderRef EInt = pure "Json.Encode.int"
    renderRef EChar = pure "Json.Encode.char"
    renderRef EBool = pure "Json.Encode.bool"
    renderRef EFloat = pure "Json.Encode.float"
    renderRef EString = pure "Json.Encode.string"
    renderRef (EList (ElmPrimitive EChar)) = pure "Json.Encode.string"
    renderRef (EList datatype) = do
      dd <- renderRef datatype
      return . parens $ "Json.Encode.list << List.map" <+> dd
    renderRef (EMaybe datatype) = do
      dd <- renderRef datatype
      return . parens $ "Maybe.withDefault Json.Encode.null << Maybe.map" <+> dd
    renderRef (ETuple2 x y) = do
      dx <- renderRef x
      dy <- renderRef y
      return . parens $ "tuple2" <+> dx <+> dy
    renderRef (EDict k v) = do
      dk <- renderRef k
      dv <- renderRef v
      return . parens $ "dict" <+> dk <+> dv
  
  toElmEncoderRefWith
    :: ElmType a
    => Options -> a -> T.Text
  toElmEncoderRefWith options x =
    pprinter $ runReader (renderRef (toElmType x)) options
  
  toElmEncoderRef
    :: ElmType a
    => a -> T.Text
  toElmEncoderRef = toElmEncoderRefWith defaultOptions
  
  toElmEncoderSourceWith
    :: ElmType a
    => Options -> a -> T.Text
  toElmEncoderSourceWith options x =
    pprinter $ runReader (render (toElmType x)) options
  
  toElmEncoderSource
    :: ElmType a
    => a -> T.Text
  toElmEncoderSource = toElmEncoderSourceWith defaultOptions
  