{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-}

module {{title}}.Types (
{{#models}}
{{#model}}
  {{classname}} (..),
{{/model}}
{{/models}}
  ) where

import Data.List (stripPrefix)
import Data.Maybe (fromMaybe)
import Data.Aeson (Value, FromJSON(..), ToJSON(..), genericToJSON, genericParseJSON)
import Data.Aeson.Types (Options(..), defaultOptions)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Map as Map
import GHC.Generics (Generic)
import Data.Function ((&))
{{#imports}}import {{import}}
{{/imports}}

{{#models}}
{{#model}}

-- | {{description}}
{{^vendorExtensions.x-customNewtype}}
{{^parent}}
{{vendorExtensions.x-data}} {{classname}} = {{classname}}
  { {{#vars}}{{& name}} :: {{datatype}} -- ^ {{& description}}{{#hasMore}}
  , {{/hasMore}}{{/vars}}
  } deriving (Show, Eq, Generic)

instance FromJSON {{classname}} where
  parseJSON = genericParseJSON (removeFieldLabelPrefix True "{{vendorExtensions.x-prefix}}")
instance ToJSON {{classname}} where
  toJSON = genericToJSON (removeFieldLabelPrefix False "{{vendorExtensions.x-prefix}}")
{{/parent}}
{{#parent}}
newtype {{classname}} = {{classname}} { un{{classname}} :: {{parent}} }
  deriving (Show, Eq, FromJSON, ToJSON, Generic)
{{/parent}}
{{/vendorExtensions.x-customNewtype}}
{{#vendorExtensions.x-customNewtype}}
newtype {{classname}} = {{classname}} {{vendorExtensions.x-customNewtype}} deriving (Show, Eq, FromJSON, ToJSON, Generic)
{{/vendorExtensions.x-customNewtype}}
{{/model}}
{{/models}}

-- Remove a field label prefix during JSON parsing.
-- Also perform any replacements for special characters.
removeFieldLabelPrefix :: Bool -> String -> Options
removeFieldLabelPrefix forParsing prefix =
  defaultOptions
  {fieldLabelModifier = fromMaybe (error ("did not find prefix " ++ prefix)) . stripPrefix prefix . replaceSpecialChars}
  where
    replaceSpecialChars field = foldl (&) field (map mkCharReplacement specialChars)
    specialChars =
      [ {{#specialCharReplacements}}("{{&char}}", "{{&replacement}}"){{#hasMore}}
      , {{/hasMore}}{{/specialCharReplacements}}
      ]
    mkCharReplacement (replaceStr, searchStr) = T.unpack . replacer (T.pack searchStr) (T.pack replaceStr) . T.pack
    replacer =
      if forParsing
        then flip T.replace
        else T.replace
