{-# 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


