{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}

module Data.EJson.Prism where

-- External Imports

import Data.Text
import Control.Lens
import Data.HashMap.Strict

-- Internal Imports

import Data.EJson.EJson


-- TODO: Remove this "helpful" documentation

-- prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
--
-- type Prism s t a b =
-- forall (p :: * -> * -> *) (f :: * -> *).
-- (Choice p, Control.Applicative.Applicative f) =>
-- p a (f b) -> p s (f t)
--
-- prism' :: (b -> s) -> (s -> Maybe a) -> Prism s s a b
--
-- preview ::
-- Control.Monad.Reader.Class.MonadReader s m =>
-- Getting (Data.Monoid.First a) s a -> m (Maybe a)
--
-- _Just :: Prism (Maybe a) (Maybe b) a b
-- _Just = prism Just $ maybe (Left Nothing) Right
--
-- _Left :: Prism (Either a c) (Either b c) a b
-- _Left = prism Left $ either Right (Left . Right)
--
-- _Right :: Prism (Either c a) (Either c b) a b
-- _Right = prism Right $ either (Left . Left) Right
--
-- _EJObject :: Text -> Prism EJsonValue (Maybe EJsonValue) EJsonValue EJsonValue

_EJObject :: Text -> Prism' EJsonValue EJsonValue
_EJObject k = prism' (const EJNull) $ f -- TODO: Does const violate prism laws?
  where f (EJObject h) = Data.HashMap.Strict.lookup k h
        f _            = Nothing

prop_ejopristest_null :: Bool
prop_ejopristest_null = EJNull ^? _EJObject "key" == Nothing

prop_ejopristest_object :: Bool
prop_ejopristest_object = ejobject [("hello","world")] ^? _EJObject "hello" == Just "world"

_EJString :: Prism' EJsonValue Text
_EJString = prism' (const EJNull) $ f -- TODO: Does const violate prism laws?
  where f (EJString s) = Just s
        f _            = Nothing

prop_ejspristest_string :: Bool
prop_ejspristest_string = ejstring "hello" ^? _EJString == Just "hello"