{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}

-- | 
-- This module defines @SymbolList@ and @Displ@ type classes
-- using by /typed-encoding/ used for display / testing as well as 
-- for construction of untyped versions of @Enc@ (@CheckedEnc@ and @UncheckedEnc@)
--
-- This module is re-exported in "Data.TypedEncoding" and it is best not to import it directly.

module Data.TypedEncoding.Common.Class.Common where

import           Data.TypedEncoding.Common.Types.Common

import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL

import           Data.Proxy
import qualified Data.List as L
import           GHC.TypeLits

-- $setup
-- >>> :set -XScopedTypeVariables -XTypeApplications -XAllowAmbiguousTypes -XDataKinds

-- * Symbol List

-- |
-- @since 0.2.0.0
class SymbolList (xs::[Symbol]) where 
    symbolVals :: [String]

instance SymbolList '[] where
    symbolVals :: [String]
symbolVals = []

-- |
-- >>> symbolVals @'["FIRST", "SECOND"]
-- ["FIRST","SECOND"]
instance (SymbolList xs, KnownSymbol x) => SymbolList (x ': xs) where
    symbolVals :: [String]
symbolVals =  Proxy @Symbol x -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy @Symbol x
forall k (t :: k). Proxy @k t
Proxy :: Proxy x) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: SymbolList xs => [String]
forall (xs :: [Symbol]). SymbolList xs => [String]
symbolVals @xs
 
symbolVals_ :: forall xs . SymbolList xs => Proxy xs -> [String]
symbolVals_ :: Proxy @[Symbol] xs -> [String]
symbolVals_ Proxy @[Symbol] xs
_ = SymbolList xs => [String]
forall (xs :: [Symbol]). SymbolList xs => [String]
symbolVals @xs

-- * Display 

-- | Human friendly version of Show
--
-- @since 0.2.0.0
class Displ x where 
    displ :: x -> String


instance Displ [EncAnn] where 
    displ :: [String] -> String
displ [String]
x = String
"[" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
L.intercalate String
"," [String]
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"]"
instance Displ T.Text where
    displ :: Text -> String
displ Text
x = String
"(Text " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
instance Displ TL.Text where
    displ :: Text -> String
displ Text
x = String
"(TL.Text " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
TL.unpack Text
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
instance Displ B.ByteString where
    displ :: ByteString -> String
displ ByteString
x = String
"(ByteString " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ByteString -> String
B.unpack ByteString
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")" 
instance Displ BL.ByteString where
    displ :: ByteString -> String
displ ByteString
x = String
"(ByteString " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ByteString -> String
BL.unpack ByteString
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"   
instance Displ String where
    displ :: String -> String
displ String
x = String
"(String " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")" 



-- |
-- >>> displ (Proxy :: Proxy ["FIRST", "SECOND"])
-- "[FIRST,SECOND]"
instance (SymbolList xs) => Displ (Proxy xs) where
    displ :: Proxy @[Symbol] xs -> String
displ Proxy @[Symbol] xs
_ = [String] -> String
forall x. Displ x => x -> String
displ ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$  SymbolList xs => [String]
forall (xs :: [Symbol]). SymbolList xs => [String]
symbolVals @xs
        -- "[" ++ (L.intercalate "," $ map displ $ symbolVals @xs) ++ "]"