module Codec.Tiled.Aeson
  ( FromJSON(..)
  , ToJSON(..)
  , genericParseJSON
  , genericToJSON
  , mkOptions
  , remapFields
  , remapFields_
  )
  where

import Data.Aeson (FromJSON(..), ToJSON(..))
import Data.Aeson qualified as Aeson
import Data.Aeson.Types (Parser)
import Data.Char (toLower)
import Data.List (dropWhileEnd)
import GHC.Generics (Generic, Rep)

genericParseJSON
  :: ( Generic a
     , Aeson.GFromJSON Aeson.Zero (Rep a)
     )
  => Aeson.Value
  -> Parser a
genericParseJSON :: forall a. (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
genericParseJSON = forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON ((String -> String) -> Options
mkOptions String -> String
remapFields)

genericToJSON
  :: ( Generic a
     , Aeson.GToJSON' Aeson.Value Aeson.Zero (Rep a)
     )
  => a
  -> Aeson.Value
genericToJSON :: forall a. (Generic a, GToJSON' Value Zero (Rep a)) => a -> Value
genericToJSON = forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON ((String -> String) -> Options
mkOptions String -> String
remapFields)

mkOptions :: (String -> String) -> Aeson.Options
mkOptions :: (String -> String) -> Options
mkOptions String -> String
fieldMods = Options
Aeson.defaultOptions
  { fieldLabelModifier :: String -> String
Aeson.fieldLabelModifier  = String -> String
fieldMods
  , omitNothingFields :: Bool
Aeson.omitNothingFields   = Bool
True
  , rejectUnknownFields :: Bool
Aeson.rejectUnknownFields = Bool
False
  }

-- | Drop trailing @_@ and convert field names to lowercase.
remapFields :: String -> String
remapFields :: String -> String
remapFields = String -> String
remapFields_ forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower

-- | Only drop trailing @_@.
remapFields_ :: String -> String
remapFields_ :: String -> String
remapFields_ = forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd (forall a. Eq a => a -> a -> Bool
== Char
'_')