module Stratosphere.Helpers
       ( maybeField
       , prefixNamer
       , prefixFieldRules
       , modTemplateJSONField
       , NamedItem (..)
       , namedItemToJSON
       , namedItemFromJSON
       ) where
import Control.Lens (set)
import Control.Lens.TH
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Char (isUpper, toLower)
import qualified Data.HashMap.Strict as HM
import Data.List (stripPrefix)
import Data.Maybe (maybeToList)
import qualified Data.Text as T
import Language.Haskell.TH
maybeField :: ToJSON a => T.Text -> Maybe a -> Maybe (T.Text, Value)
maybeField field = fmap ((field .=) . toJSON)
prefixNamer :: String -> Name -> [Name] -> Name -> [DefName]
prefixNamer prefix _ _ field = maybeToList $
  do
    fieldPart <- stripPrefix prefix (nameBase field)
    method    <- computeMethod fieldPart
    let cls = "Has" ++ fieldPart
    return (MethodName (mkName cls) (mkName method))
    where computeMethod (x:xs) | isUpper x = Just (toLower x : xs)
          computeMethod _                  = Nothing
prefixFieldRules :: String -> LensRules
prefixFieldRules prefix = set lensField (prefixNamer prefix) defaultFieldRules
modTemplateJSONField :: String -> String
modTemplateJSONField "templateFormatVersion" = "AWSTemplateFormatVersion"
modTemplateJSONField s = drop 8 s
class NamedItem a where
  itemName :: a -> T.Text
  nameToJSON :: a -> Value
  nameParseJSON :: T.Text -> Object -> Parser a
namedItemToJSON :: (NamedItem a) => [a] -> Value
namedItemToJSON xs =
    object $ fmap (\x -> itemName x .= nameToJSON x) xs
namedItemFromJSON :: (NamedItem a) => Value -> Parser [a]
namedItemFromJSON v = do
    objs <- parseJSON v :: Parser (HM.HashMap T.Text Value)
    sequence [withObject "NamedItem" (nameParseJSON n) obj |
              (n, obj) <- HM.toList objs]