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

-- | Combinators reexported in Data.TypedEncoding.
-- 
-- Decoding combinators that are backward compatible to v0.2 versions.
--
-- @since 0.3.0.0
module Data.TypedEncoding.Combinators.Encode where

import           Data.TypedEncoding.Common.Types.Enc
import           Data.TypedEncoding.Common.Util.TypeLits -- Append
import           Data.TypedEncoding.Combinators.Common
import           Data.TypedEncoding.Common.Class.Encode
import           GHC.TypeLits
import           Data.Functor.Identity


-- * Convenience combinators which mimic pre-v0.3 type signatures. These assume that @algs@ are the same as @nms@

encodeF :: forall nm xs f c str . Encode f nm nm c str => Enc xs c str -> f (Enc (nm ': xs) c str)
encodeF :: Enc @[Symbol] xs c str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) c str)
encodeF = forall (xs :: [Symbol]) (f :: * -> *) c str.
Encode f nm nm c str =>
Enc @[Symbol] xs c str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) c str)
forall (alg :: Symbol) (nm :: Symbol) (xs :: [Symbol])
       (f :: * -> *) c str.
Encode f nm alg c str =>
Enc @[Symbol] xs c str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) c str)
encodeF' @nm @nm

encodeFAll :: forall nms f c str . (Monad f,  EncodeAll f nms nms c str) =>  
               Enc ('[]::[Symbol]) c str 
               -> f (Enc nms c str)  
encodeFAll :: Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
encodeFAll = forall (algs :: [Symbol]) (nms :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f nms algs c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
forall (f :: * -> *) c str.
(Monad f, EncodeAll f nms nms c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
encodeFAll' @nms @nms

encodeAll :: forall nms c str . (EncodeAll Identity nms nms c str) =>
               Enc ('[]::[Symbol]) c str 
               -> Enc nms c str 
encodeAll :: Enc @[Symbol] ('[] @Symbol) c str -> Enc @[Symbol] nms c str
encodeAll = forall (algs :: [Symbol]) (nms :: [Symbol]) c str.
EncodeAll Identity nms algs c str =>
Enc @[Symbol] ('[] @Symbol) c str -> Enc @[Symbol] nms c str
forall c str.
EncodeAll Identity nms nms c str =>
Enc @[Symbol] ('[] @Symbol) c str -> Enc @[Symbol] nms c str
encodeAll' @nms @nms 

encodeFPart :: forall xs xsf f c str . (Monad f, EncodeAll f xs xs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str)
encodeFPart :: Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
encodeFPart = forall (algs :: [Symbol]) (xs :: [Symbol]) (xsf :: [Symbol])
       (f :: * -> *) c str.
(Monad f, EncodeAll f xs algs c str) =>
Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
forall (xsf :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f xs xs c str) =>
Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
encodeFPart' @xs @xs

encodePart :: forall xs xsf c str . (EncodeAll Identity xs xs c str) => Enc xsf c str -> Enc (Append xs xsf) c str   
encodePart :: Enc @[Symbol] xsf c str
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
encodePart = forall (algs :: [Symbol]) (xs :: [Symbol]) (xsf :: [Symbol]) c str.
EncodeAll Identity xs algs c str =>
Enc @[Symbol] xsf c str
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
forall (xsf :: [Symbol]) c str.
EncodeAll Identity xs xs c str =>
Enc @[Symbol] xsf c str
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
encodePart' @xs @xs


-- * Convenience combinators which mimic pre-v0.3 type signatures. These do not try to figure out @algs@ or assume much about them

encodeF' :: forall alg nm xs f c str . (Encode f nm alg c str) => Enc xs c str -> f (Enc (nm ': xs) c str)
encodeF' :: Enc @[Symbol] xs c str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) c str)
encodeF' = Encoding f nm alg c str
-> Enc @[Symbol] xs c str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) c str)
forall (alg :: Symbol) (nm :: Symbol) (f :: * -> *)
       (xs :: [Symbol]) conf str.
Encoding f nm alg conf str
-> Enc @[Symbol] xs conf str
-> f (Enc @[Symbol] ((':) @Symbol nm xs) conf str)
runEncoding' (forall conf str.
Encode f nm alg conf str =>
Encoding f nm alg conf str
forall (f :: * -> *) (nm :: Symbol) (alg :: Symbol) conf str.
Encode f nm alg conf str =>
Encoding f nm alg conf str
encoding @f @nm @alg)

encodeFAll' :: forall algs nms f c str . (Monad f,  EncodeAll f nms algs c str) =>  
               Enc ('[]::[Symbol]) c str 
               -> f (Enc nms c str)  
encodeFAll' :: Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
encodeFAll' = Encodings f nms algs c str
-> Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
forall (algs :: [Symbol]) (nms :: [Symbol]) (f :: * -> *) c str.
Monad f =>
Encodings f nms algs c str
-> Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
runEncodings' @algs @nms @f Encodings f nms algs c str
forall (f :: * -> *) (nms :: [Symbol]) (algs :: [Symbol]) conf str.
EncodeAll f nms algs conf str =>
Encodings f nms algs conf str
encodings 

-- | 
-- 
encodeAll' :: forall algs nms c str . (EncodeAll Identity nms algs c str) =>
               Enc ('[]::[Symbol]) c str 
               -> Enc nms c str 
encodeAll' :: Enc @[Symbol] ('[] @Symbol) c str -> Enc @[Symbol] nms c str
encodeAll' = Identity (Enc @[Symbol] nms c str) -> Enc @[Symbol] nms c str
forall a. Identity a -> a
runIdentity (Identity (Enc @[Symbol] nms c str) -> Enc @[Symbol] nms c str)
-> (Enc @[Symbol] ('[] @Symbol) c str
    -> Identity (Enc @[Symbol] nms c str))
-> Enc @[Symbol] ('[] @Symbol) c str
-> Enc @[Symbol] nms c str
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (algs :: [Symbol]) (nms :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f nms algs c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
forall (nms :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f nms algs c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
encodeFAll' @algs 

encodeFPart' :: forall algs xs xsf f c str . (Monad f, EncodeAll f xs algs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str)
encodeFPart' :: Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
encodeFPart' = (Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] xs c str))
-> Enc @[Symbol] (Append @Symbol ('[] @Symbol) xsf) c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
forall (ts :: [Symbol]) (xs :: [Symbol]) (ys :: [Symbol])
       (f :: * -> *) c str.
Functor f =>
(Enc @[Symbol] xs c str -> f (Enc @[Symbol] ys c str))
-> Enc @[Symbol] (Append @Symbol xs ts) c str
-> f (Enc @[Symbol] (Append @Symbol ys ts) c str)
aboveF @xsf @'[] @xs (forall (algs :: [Symbol]) (nms :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f nms algs c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
forall (nms :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f nms algs c str) =>
Enc @[Symbol] ('[] @Symbol) c str -> f (Enc @[Symbol] nms c str)
encodeFAll' @algs) 
-- encodeFPart' (UnsafeMkEnc _ conf str) =  
--     let re :: f (Enc xs c str) = encodeFAll' @algs $ UnsafeMkEnc Proxy conf str
--     in  UnsafeMkEnc Proxy conf . getPayload <$> re

encodePart' :: forall algs xs xsf c str . (EncodeAll Identity xs algs c str) => Enc xsf c str -> Enc (Append xs xsf) c str   
encodePart' :: Enc @[Symbol] xsf c str
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
encodePart' = Identity (Enc @[Symbol] (Append @Symbol xs xsf) c str)
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
forall a. Identity a -> a
runIdentity (Identity (Enc @[Symbol] (Append @Symbol xs xsf) c str)
 -> Enc @[Symbol] (Append @Symbol xs xsf) c str)
-> (Enc @[Symbol] xsf c str
    -> Identity (Enc @[Symbol] (Append @Symbol xs xsf) c str))
-> Enc @[Symbol] xsf c str
-> Enc @[Symbol] (Append @Symbol xs xsf) c str
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (algs :: [Symbol]) (xs :: [Symbol]) (xsf :: [Symbol])
       (f :: * -> *) c str.
(Monad f, EncodeAll f xs algs c str) =>
Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
forall (xsf :: [Symbol]) (f :: * -> *) c str.
(Monad f, EncodeAll f xs algs c str) =>
Enc @[Symbol] xsf c str
-> f (Enc @[Symbol] (Append @Symbol xs xsf) c str)
encodeFPart' @algs @xs