module IHP.InputValue
( InputValue (..)
) where

import Prelude
import Data.Text (Text)
import qualified Data.Text as Text
import Data.UUID (UUID)
import qualified Data.UUID as UUID
import Data.Time.Clock (UTCTime)
import Data.Time.LocalTime (LocalTime, TimeOfDay)
import Data.Time.Calendar (Day)
import Data.Time.Format.ISO8601 (iso8601Show)
import Data.Aeson (Value)
import qualified Data.Aeson as Aeson
import Data.Scientific (Scientific)
import Data.String.Conversions (cs)
import qualified Numeric
import PostgresqlTypes.Interval (Interval)
import PostgresqlTypes.Inet (Inet)

-- | Provides a way to convert a Haskell value to a Text representation
-- for use in HTML @\<input value="..."\/>@ attributes.
--
-- This is used by IHP's form helpers to populate form field values.
--
-- __Example:__
--
-- >>> inputValue True
-- "on"
--
-- >>> inputValue (1 :: Int)
-- "1"
--
class InputValue a where
    inputValue :: a -> Text

instance InputValue Text where
    inputValue :: Text -> Text
inputValue Text
text = Text
text

instance InputValue Int where
    inputValue :: Int -> Text
inputValue = String -> Text
Text.pack (String -> Text) -> (Int -> String) -> Int -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show

instance InputValue Integer where
    inputValue :: Integer -> Text
inputValue = String -> Text
Text.pack (String -> Text) -> (Integer -> String) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show

instance InputValue Double where
    inputValue :: Double -> Text
inputValue Double
double = String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (Maybe Int -> Double -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
Numeric.showFFloat Maybe Int
forall a. Maybe a
Nothing Double
double String
"")

instance InputValue Float where
    inputValue :: Float -> Text
inputValue Float
float = String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (Maybe Int -> Float -> ShowS
forall a. RealFloat a => Maybe Int -> a -> ShowS
Numeric.showFFloat Maybe Int
forall a. Maybe a
Nothing Float
float String
"")

instance InputValue Bool where
    inputValue :: Bool -> Text
inputValue Bool
True = Text
"on"
    inputValue Bool
False = Text
"off"

instance InputValue UUID where
    inputValue :: UUID -> Text
inputValue = UUID -> Text
UUID.toText

instance InputValue () where
    inputValue :: () -> Text
inputValue () = Text
"error: inputValue(()) not supported"

instance InputValue UTCTime where
    inputValue :: UTCTime -> Text
inputValue UTCTime
time = String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (UTCTime -> String
forall t. ISO8601 t => t -> String
iso8601Show UTCTime
time)

instance InputValue LocalTime where
    inputValue :: LocalTime -> Text
inputValue LocalTime
time = String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (LocalTime -> String
forall t. ISO8601 t => t -> String
iso8601Show LocalTime
time)

instance InputValue Day where
    inputValue :: Day -> Text
inputValue Day
date = String -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (Day -> String
forall t. ISO8601 t => t -> String
iso8601Show Day
date)

instance InputValue TimeOfDay where
    inputValue :: TimeOfDay -> Text
inputValue TimeOfDay
timeOfDay = String -> Text
Text.pack (TimeOfDay -> String
forall a. Show a => a -> String
show TimeOfDay
timeOfDay)

instance InputValue Interval where
    inputValue :: Interval -> Text
inputValue Interval
interval = String -> Text
Text.pack (Interval -> String
forall a. Show a => a -> String
show Interval
interval)

instance InputValue Inet where
    inputValue :: Inet -> Text
inputValue Inet
inet = String -> Text
Text.pack (Inet -> String
forall a. Show a => a -> String
show Inet
inet)

instance InputValue fieldType => InputValue (Maybe fieldType) where
    inputValue :: Maybe fieldType -> Text
inputValue (Just fieldType
value) = fieldType -> Text
forall a. InputValue a => a -> Text
inputValue fieldType
value
    inputValue Maybe fieldType
Nothing = Text
""

instance InputValue value => InputValue [value] where
    inputValue :: [value] -> Text
inputValue [value]
list = Text -> [Text] -> Text
Text.intercalate Text
"," ((value -> Text) -> [value] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map value -> Text
forall a. InputValue a => a -> Text
inputValue [value]
list)

instance InputValue Value where
    inputValue :: Value -> Text
inputValue Value
json = ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
cs (Value -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode Value
json)

instance InputValue Scientific where
    inputValue :: Scientific -> Text
inputValue = String -> Text
Text.pack (String -> Text) -> (Scientific -> String) -> Scientific -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> String
forall a. Show a => a -> String
show