{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE ScopedTypeVariables        #-}
module Language.Haskell.Homplexity.Metric (
    Metric (..)
  , LOC
  , locT
  , measureAs
  , measureFor
  ) where
import           Data.Data
import           Data.Function
import           Control.Arrow
import           Data.Generics.Uniplate.Data
import           Data.List
import           Language.Haskell.Exts.SrcLoc
import           Language.Haskell.Homplexity.CodeFragment
class (CodeFragment c, Show m) => Metric m c where
  measure :: c -> m
newtype LOC = LOC { _asInt :: Int }
  deriving (Ord, Eq, Enum, Num, Real, Integral)
locT :: Proxy LOC
locT  = Proxy
instance Show LOC where
  showsPrec _ (LOC l) = shows l . (" lines of code"++)
instance Read LOC where
  readsPrec prec str = first LOC <$> readsPrec prec str
instance (CodeFragment c) => Metric LOC c where
  measure = LOC
          . length                          
          . concatMap (nub . map srcLine)   
          . groupBy ((==) `on` srcFilename) 
          . universeBi                      
measureAs :: (Metric m c) => Proxy m -> c -> m
measureAs _ = measure
measureFor :: (Metric m c) => Proxy m -> Proxy c -> c -> m
measureFor _ _ = measure