{-# LANGUAGE ConstraintKinds, CPP, DataKinds, FlexibleContexts,
             FlexibleInstances, KindSignatures, MultiParamTypeClasses,
             PolyKinds, ScopedTypeVariables, TypeFamilies,
             TypeOperators, UndecidableInstances, TemplateHaskell,
             QuasiQuotes, Rank2Types, TypeApplications,
             AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Frames.ExtraInstances where

import Data.Functor.Contravariant
import Data.Functor.Contravariant.Divisible
import Data.Discrimination.Grouping
import Data.Hashable
import Control.DeepSeq
import Frames.Col
import Frames.Rec
import Frames.Frame
import Frames.RecF (AllCols)
import Data.Vinyl.Functor as VF
import Data.Vinyl
import Data.Text (Text)

-- Grouping instances
instance (AllCols Grouping rs
         , Grouping (Record rs)
         , Grouping (ElField (s :-> r))
         , Grouping r
         ) =>
         Grouping (Record ((s :-> r) : rs)) where
  grouping = divide recUncons grouping grouping

instance Grouping (Record '[]) where
  grouping = conquer

instance (Grouping a) => Grouping (ElField (s :-> a)) where
   grouping = contramap getCol grouping

instance Grouping Text where
  grouping = contramap hash grouping


-- NFData* instances
#if MIN_VERSION_deepseq(1,4,3)
instance (NFData a) =>
         NFData (VF.Identity a) where
  rnf = rnf1

instance NFData1 VF.Identity where
  liftRnf r = r . getIdentity

instance (NFData (f r), NFData (Rec f rs)) => NFData (Rec f (r ': rs)) where
  rnf (x :& xs) = rnf x `seq` rnf xs

instance NFData (Rec f '[]) where
  rnf RNil = ()

instance (NFData1 f, NFData1 g) => NFData1 (Compose f g) where
  liftRnf f = liftRnf (liftRnf f) . getCompose

instance NFData (f (g a)) => NFData (Compose f g a) where
  rnf (Compose x) = rnf x

#endif


instance (NFData a) =>
         NFData (Frame a) where
  rnf = foldr (\x acc -> rnf x `seq` acc) ()

instance (NFData a) => NFData (ElField (s :-> a)) where
  rnf = rnf . getCol