{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
-- | Types for defining JSON schemas.
module Data.JSON.Schema.Types where

import Data.Maybe
import Data.Proxy
import Data.Text (Text)
import Data.Word (Word32)

-- | A schema is any JSON value.
type Schema = Value

-- | A schema for a JSON value.
data Value =
    Choice [Value] -- ^ A choice of multiple values, e.g. for sum types.
  | Object [Field] -- ^ A JSON object.
  | Array Int Int Bool Value -- ^ An array. The integers represent the
                             -- lower and upper bound of the array
                             -- size. The value -1 indicates no bound.
                             -- The boolean denotes whether items have
                             -- to unique.
  | Tuple [Value]   -- ^ A fixed-length tuple of different values.
  | Value Int Int   -- ^ A string. The integers denote the lower and
                    -- upper bound of the length of the string. The
                    -- value -1 indicates no bound.
  | Boolean
  | Number Int Int  -- ^ A number. The integers denote the lower and
                    -- upper bound on the value. The value -1
                    -- indicates no bound.
  | Null
  deriving (Eq, Show)

-- | A field in an object.
data Field = Field { key :: String, required :: Bool, content :: Schema } deriving (Eq, Show)

-- | Class representing JSON schemas
class JSONSchema a where
  schema :: Proxy a -> Schema

instance JSONSchema () where
  schema _ = Null

instance JSONSchema Int where
  schema _ = Number 0 (-1)

instance JSONSchema Integer where
  schema _ = Number 0 (-1)

instance JSONSchema Word32 where
  schema _ = Number 0 4294967295

instance JSONSchema Bool where
  schema _ = Boolean

instance JSONSchema Text where
  schema _ = Value 0 (-1)

instance JSONSchema a => JSONSchema (Maybe a) where
  schema p = Choice [Object [Field "Just" True $ schema $ fmap fromJust p], Object [Field "Nothing" True Null]]

instance JSONSchema a => JSONSchema [a] where
  schema = Array 0 (-1) False . schema . fmap head