content: {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses      #-}
  -- | Measuring the complexity of type class declarations
  module Language.Haskell.Homplexity.TypeClassComplexity
    ( NonTypeDeclCount
    , nonTypeDeclCountT
    , AssocTypeCount
    , assocTypeCountT
    ) where
  
  import           Data.Data
  import           Data.Generics.Uniplate.Data              ()
  import           Data.Maybe
  --import Language.Haskell.Exts.SrcLoc
  import           Language.Haskell.Exts.Syntax
  import           Language.Haskell.Homplexity.CodeFragment
  import           Language.Haskell.Homplexity.Metric
  import           Language.Haskell.Homplexity.Utilities
  
  -- NOTE: It is non-trivial to decide whether a class declaration
  -- is a method or a value. To correctly do that, we would have to
  -- see through type synonyms. So, we will aggregate methods and values.
  
  -- * Type class method count
  -- | Represents the number of methods and value in a type class.
  newtype NonTypeDeclCount = NonTypeDeclCount { unNonTypeDeclCount :: Int }
    deriving (Eq, Ord, Enum, Num, Real, Integral)
  
  -- | For passing @NonTypeDeclCount@ type as parameter.
  nonTypeDeclCountT :: Proxy NonTypeDeclCount
  nonTypeDeclCountT  = Proxy
  
  instance Show NonTypeDeclCount where
    showsPrec _ (NonTypeDeclCount mc) = ("method + value count of " ++)
                                      . shows mc
  
  instance Metric NonTypeDeclCount TypeClass where
    measure = NonTypeDeclCount . sumOf method . fromMaybe [] . tcDecls where
  
      method :: ClassDecl l -> Int
      method (ClsDecl _ TypeSig{}) = 1
      method _                     = 0
  
  -- * Type class associated types count
  -- | Represents the number of associated types in a type class.
  -- It includes both associated type and data families.
  newtype AssocTypeCount = AssocTypeCount { unAssocTypeCount :: Int }
    deriving (Eq, Ord, Enum, Num, Real, Integral)
  
  -- | For passing @AssocTypeCount@ type as parameter.
  assocTypeCountT :: Proxy AssocTypeCount
  assocTypeCountT  = Proxy
  
  instance Show AssocTypeCount where
    showsPrec _ (AssocTypeCount atc) = ("associated type count of " ++)
                                     . shows atc
  
  instance Metric AssocTypeCount TypeClass where
    measure = AssocTypeCount . sumOf assocType . fromMaybe [] . tcDecls where
  
      assocType :: ClassDecl l -> Int
      assocType ClsTyFam{}   = 1
      assocType ClsTyDef{}   = 1
      assocType ClsDataFam{} = 1
      assocType _            = 0
  